From: Michael Rolnik <mrolnik@gmail.com>
To: qemu-devel@nongnu.org
Subject: [Qemu-devel] Initial commit of AVR cores
Date: Sun, 29 May 2016 01:57:41 -0700 [thread overview]
Message-ID: <CAK4993gh8De=RsYfPdhN31Rv=1vUCBaQceSeMsZFH2-iwr-kig@mail.gmail.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 410 bytes --]
1. Initial commit of AVR 8bit cores support
2. all instruction, except BREAK/DES/SPM/SPMX, are implemented
3. not fully tested yet, however I was able to execute simple code with
functions. e.g fibonacci calculation
4. the current patch includes a non real, sample board
5. this patch does not include any peripheral devices.
6. no fuses support yet. PC is set to 0 at reset.
--
Best Regards,
Michael Rolnik
[-- Attachment #2: 0001-Initial-commit-of-AVR-core.patch --]
[-- Type: application/octet-stream, Size: 258390 bytes --]
From f1a8f6a69dcd5788bf20cd4cedc97461fc4f395c Mon Sep 17 00:00:00 2001
From: Michael Rolnik <rolnik@amazon.com>
Date: Tue, 10 May 2016 01:16:39 +0300
Subject: [PATCH] Initial commit of AVR core
Signed-off-by: Michael Rolnik <mrolnik@gmail.com>
---
arch_init.c | 2 +
configure | 5 +
default-configs/avr-softmmu.mak | 1 +
disas/Makefile.objs | 1 +
disas/avr.c | 10 +
gdbstub.c | 4 +-
hw/Makefile.objs | 1 +
hw/avr/Makefile.objs | 1 +
hw/avr/sample-io.c | 246 ++++
hw/avr/sample.c | 120 ++
include/disas/bfd.h | 7 +
include/sysemu/arch_init.h | 1 +
target-avr/Makefile.objs | 5 +
target-avr/cpu-qom.h | 97 ++
target-avr/cpu.c | 637 +++++++++
target-avr/cpu.h | 211 +++
target-avr/decode.c | 740 +++++++++++
target-avr/decode.h | 1016 +++++++++++++++
target-avr/gdbstub.c | 105 ++
target-avr/helper.c | 280 ++++
target-avr/helper.h | 26 +
target-avr/machine.c | 54 +
target-avr/machine.h | 21 +
target-avr/translate.c | 370 ++++++
target-avr/translate.c.inc | 2701 +++++++++++++++++++++++++++++++++++++++
25 files changed, 6659 insertions(+), 3 deletions(-)
create mode 100644 default-configs/avr-softmmu.mak
create mode 100644 disas/avr.c
create mode 100644 hw/avr/Makefile.objs
create mode 100644 hw/avr/sample-io.c
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/decode.c
create mode 100644 target-avr/decode.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/machine.h
create mode 100644 target-avr/translate.c
create mode 100644 target-avr/translate.c.inc
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 b5aab72..90af399 100755
--- a/configure
+++ b/configure
@@ -5630,6 +5630,8 @@ case "$target_name" in
x86_64)
TARGET_BASE_ARCH=i386
;;
+ avr)
+ ;;
alpha)
;;
arm|armeb)
@@ -5826,6 +5828,9 @@ disas_config() {
for i in $ARCH $TARGET_BASE_ARCH ; do
case "$i" in
+ avr)
+ disas_config "AVR"
+ ;;
alpha)
disas_config "ALPHA"
;;
diff --git a/default-configs/avr-softmmu.mak b/default-configs/avr-softmmu.mak
new file mode 100644
index 0000000..ca94aad
--- /dev/null
+++ b/default-configs/avr-softmmu.mak
@@ -0,0 +1 @@
+# Default configuration for avr-softmmu
diff --git a/disas/Makefile.objs b/disas/Makefile.objs
index abeba84..218e434 100644
--- a/disas/Makefile.objs
+++ b/disas/Makefile.objs
@@ -21,6 +21,7 @@ common-obj-$(CONFIG_S390_DIS) += s390.o
common-obj-$(CONFIG_SH4_DIS) += sh4.o
common-obj-$(CONFIG_SPARC_DIS) += sparc.o
common-obj-$(CONFIG_LM32_DIS) += lm32.o
+common-obj-$(CONFIG_AVR_DIS) += avr.o
# TODO: As long as the TCG interpreter and its generated code depend
# on the QEMU target, we cannot compile the disassembler here.
diff --git a/disas/avr.c b/disas/avr.c
new file mode 100644
index 0000000..f916e72
--- /dev/null
+++ b/disas/avr.c
@@ -0,0 +1,10 @@
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "disas/bfd.h"
+
+int print_insn_avr(bfd_vma addr, disassemble_info *info)
+{
+ int length = 0;;
+ /* TODO */
+ return length;
+}
diff --git a/gdbstub.c b/gdbstub.c
index b9e3710..21e88b8 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -270,8 +270,6 @@ static int gdb_signal_to_target (int sig)
return -1;
}
-//#define DEBUG_GDB
-
typedef struct GDBRegisterState {
int base_reg;
int num_regs;
@@ -313,7 +311,7 @@ typedef struct GDBState {
/* By default use no IRQs and no timers while single stepping so as to
* make single stepping like an ICE HW step.
*/
-static int sstep_flags = SSTEP_ENABLE|SSTEP_NOIRQ|SSTEP_NOTIMER;
+static int sstep_flags = SSTEP_ENABLE | SSTEP_NOIRQ | SSTEP_NOTIMER;
static GDBState *gdbserver_state;
diff --git a/hw/Makefile.objs b/hw/Makefile.objs
index 4a07ed4..262ca15 100644
--- a/hw/Makefile.objs
+++ b/hw/Makefile.objs
@@ -33,6 +33,7 @@ devices-dirs-$(CONFIG_SOFTMMU) += watchdog/
devices-dirs-$(CONFIG_SOFTMMU) += xen/
devices-dirs-$(CONFIG_MEM_HOTPLUG) += mem/
devices-dirs-$(CONFIG_SMBIOS) += smbios/
+devices-dirs-$(CONFIG_SOFTMMU) += avr/
devices-dirs-y += core/
common-obj-y += $(devices-dirs-y)
obj-y += $(devices-dirs-y)
diff --git a/hw/avr/Makefile.objs b/hw/avr/Makefile.objs
new file mode 100644
index 0000000..9f6be2f
--- /dev/null
+++ b/hw/avr/Makefile.objs
@@ -0,0 +1 @@
+obj-y += sample.o sample-io.o
diff --git a/hw/avr/sample-io.c b/hw/avr/sample-io.c
new file mode 100644
index 0000000..133c72f
--- /dev/null
+++ b/hw/avr/sample-io.c
@@ -0,0 +1,246 @@
+/*
+ * 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 "qemu-common.h"
+#include "cpu.h"
+#include "include/hw/sysbus.h"
+
+#define TYPE_SAMPLEIO "SampleIO"
+#define SAMPLEIO(obj) OBJECT_CHECK(SAMPLEIOState, (obj), TYPE_SAMPLEIO)
+
+#ifndef DEBUG_SAMPLEIO
+#define DEBUG_SAMPLEIO 1
+#endif
+
+#define DPRINTF(fmt, args...) \
+ do { \
+ if (DEBUG_SAMPLEIO) { \
+ fprintf(stderr, "[%s]%s: " fmt , TYPE_SAMPLEIO, __func__, ##args);\
+ } \
+ } \
+ while (0)
+
+#define AVR_IO_CPU_REGS_SIZE 0x0020
+#define AVR_IO_CPU_IO_SIZE 0x0040
+#define AVR_IO_EXTERN_IO_SIZE 0x00a0
+#define AVR_IO_SIZE (AVR_IO_CPU_REGS_SIZE \
+ + AVR_IO_CPU_IO_SIZE \
+ + AVR_IO_EXTERN_IO_SIZE)
+
+#define AVR_IO_CPU_REGS_BASE 0x0000
+#define AVR_IO_CPU_IO_BASE (AVR_IO_CPU_REGS_BASE \
+ + AVR_IO_CPU_REGS_SIZE)
+#define AVR_IO_EXTERN_IO_BASE (AVR_IO_CPU_IO_BASE \
+ + AVR_IO_CPU_IO_SIZE)
+
+
+typedef struct SAMPLEIOState {
+ SysBusDevice parent;
+
+ MemoryRegion iomem;
+
+ AVRCPU *cpu;
+
+ uint8_t io[0x40];
+ uint8_t exio[0xa0];
+} SAMPLEIOState;
+
+static uint64_t sample_io_read(
+ void *opaque,
+ hwaddr offset,
+ unsigned size);
+static void sample_io_write(void *opaque,
+ hwaddr offset,
+ uint64_t value,
+ unsigned size);
+static int sample_io_init(
+ DeviceState *sbd);
+static void sample_io_class_init(
+ ObjectClass *klass,
+ void *data);
+static void sample_io_register_types(void);
+
+static void write_Rx(
+ CPUAVRState *env,
+ int inst,
+ uint8_t data);
+static uint8_t read_Rx(
+ CPUAVRState *env,
+ int inst);
+
+static const
+MemoryRegionOps sample_io_ops = {
+ .read = sample_io_read,
+ .write = sample_io_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static
+Property sample_io_properties[] = {
+ DEFINE_PROP_END_OF_LIST(),
+};
+static const
+VMStateDescription sample_io_vmstate = {
+ .name = TYPE_SAMPLEIO,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[])
+ {
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+void write_Rx(
+ CPUAVRState *env,
+ int inst,
+ uint8_t data)
+{
+ env->r[inst] = data;
+}
+uint8_t read_Rx(
+ CPUAVRState *env,
+ int inst)
+{
+ return env->r[inst];
+}
+
+static
+void sample_io_reset(DeviceState *dev)
+{
+ DPRINTF("\n");
+}
+
+static
+uint64_t sample_io_read(
+ void *opaque,
+ hwaddr offset,
+ unsigned size)
+{
+ SAMPLEIOState *s = SAMPLEIO(opaque);
+ AVRCPU *cpu = s->cpu;
+ CPUAVRState *env = &cpu->env;
+ uint64_t res = 0;
+
+ assert(size == 1);
+
+ if (AVR_IO_CPU_REGS_BASE <= offset
+ && offset < (AVR_IO_CPU_REGS_BASE + AVR_IO_CPU_REGS_SIZE)) {
+ res = read_Rx(env, offset - AVR_IO_CPU_REGS_BASE);
+ } else if (AVR_IO_CPU_IO_BASE <= offset
+ && offset < (AVR_IO_CPU_IO_BASE + AVR_IO_CPU_IO_SIZE)) {
+ /* TODO: do IO related stuff here */
+ res = s->io[offset - AVR_IO_CPU_IO_BASE];
+ } else if (AVR_IO_EXTERN_IO_BASE <= offset
+ && offset < (AVR_IO_EXTERN_IO_BASE + AVR_IO_EXTERN_IO_SIZE)) {
+ /* TODO: do IO related stuff here */
+ res = s->io[offset - AVR_IO_EXTERN_IO_BASE];
+ } else {
+ g_assert_not_reached();
+ }
+
+ return res;
+}
+
+static
+void sample_io_write(
+ void *opaque,
+ hwaddr offset,
+ uint64_t value,
+ unsigned size)
+{
+ SAMPLEIOState *s = SAMPLEIO(opaque);
+ AVRCPU *cpu = s->cpu;
+ CPUAVRState *env = &cpu->env;
+
+ assert(size == 1);
+
+ if (AVR_IO_CPU_REGS_BASE <= offset
+ && offset < (AVR_IO_CPU_REGS_BASE + AVR_IO_CPU_REGS_SIZE)) {
+ return write_Rx(env, offset - AVR_IO_CPU_REGS_BASE, value);
+ } else if (AVR_IO_CPU_IO_BASE <= offset
+ && offset < (AVR_IO_CPU_IO_BASE + AVR_IO_CPU_IO_SIZE)) {
+ /* TODO: do IO related stuff here */
+ s->io[offset - AVR_IO_CPU_IO_BASE] = value;
+ } else if (AVR_IO_EXTERN_IO_BASE <= offset
+ && offset < (AVR_IO_EXTERN_IO_BASE + AVR_IO_EXTERN_IO_SIZE)) {
+ /* TODO: do IO related stuff here */
+ s->io[offset - AVR_IO_EXTERN_IO_BASE] = value;
+ } else {
+ g_assert_not_reached();
+ }
+}
+
+static
+int sample_io_init(
+ DeviceState *dev)
+{
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+ SAMPLEIOState *s = SAMPLEIO(dev);
+
+ assert(AVR_IO_SIZE <= TARGET_PAGE_SIZE);
+
+ s->cpu = AVR_CPU(qemu_get_cpu(0));
+
+ memory_region_init_io(
+ &s->iomem,
+ OBJECT(s),
+ &sample_io_ops,
+ s,
+ TYPE_SAMPLEIO,
+ AVR_IO_SIZE);
+ sysbus_init_mmio(sbd, &s->iomem);
+
+ return 0;
+}
+
+static
+void sample_io_class_init(
+ ObjectClass *klass,
+ void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ DPRINTF("\n");
+
+ dc->init = sample_io_init;
+ dc->reset = sample_io_reset;
+ dc->desc = "at90 io regs";
+ dc->vmsd = &sample_io_vmstate;
+ dc->props = sample_io_properties;
+}
+
+static const
+TypeInfo sample_io_info = {
+ .name = TYPE_SAMPLEIO,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SAMPLEIOState),
+ .class_init = sample_io_class_init,
+};
+
+static
+void sample_io_register_types(void)
+{
+ DPRINTF("\n");
+ type_register_static(&sample_io_info);
+}
+
+type_init(sample_io_register_types)
diff --git a/hw/avr/sample.c b/hw/avr/sample.c
new file mode 100644
index 0000000..d8b9d5c
--- /dev/null
+++ b/hw/avr/sample.c
@@ -0,0 +1,120 @@
+/*
+ * 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 "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_IOREG 0x00000000
+#define VIRT_BASE_ISRAM 0x00000100
+#define VIRT_BASE_EXMEM 0x00001100
+#define VIRT_BASE_EEPROM 0x00000000
+
+#define VIRT_BASE_BOOT 0x0001e000
+#define PHYS_BASE_BOOT (PHYS_BASE_FLASH + VIRT_BASE_BOOT)
+
+#define SIZE_FLASH 0x00020000
+#define SIZE_IOREG 0x00000100
+#define SIZE_ISRAM 0x00001000
+#define SIZE_EXMEM 0x00010000
+#define SIZE_EEPROM 0x00001000
+
+#define PHYS_BASE_FLASH (PHYS_CODE_BASE)
+#define PHYS_BASE_IOREG (PHYS_DATA_BASE)
+#define PHYS_BASE_ISRAM (PHYS_BASE_IOREG + SIZE_IOREG)
+#define PHYS_BASE_EXMEM (PHYS_BASE_ISRAM + SIZE_ISRAM)
+#define PHYS_BASE_EEPROM (PHYS_BASE_EXMEM + SIZE_EXMEM)
+
+
+static
+void sample_init(MachineState *machine)
+{
+ MemoryRegion *address_space_mem = get_system_memory();
+
+ MemoryRegion *flash;
+ MemoryRegion *isram;
+ MemoryRegion *exmem;
+
+ AVRCPU *cpu_avr;
+ DeviceState *io;
+ SysBusDevice *bus;
+
+ flash = g_new(MemoryRegion, 1);
+ isram = g_new(MemoryRegion, 1);
+ exmem = g_new(MemoryRegion, 1);
+
+ cpu_avr = cpu_avr_init("avr5");
+ io = qdev_create(NULL, "SampleIO");
+ bus = SYS_BUS_DEVICE(io);
+ qdev_init_nofail(io);
+
+ memory_region_init_ram(flash, NULL, "flash", SIZE_FLASH, &error_fatal);
+ memory_region_init_ram(isram, NULL, "isram", SIZE_ISRAM, &error_fatal);
+ memory_region_init_ram(exmem, NULL, "exmem", SIZE_EXMEM, &error_fatal);
+
+ memory_region_add_subregion(address_space_mem, PHYS_BASE_FLASH, flash);
+ memory_region_add_subregion(address_space_mem, PHYS_BASE_ISRAM, isram);
+ memory_region_add_subregion(address_space_mem, PHYS_BASE_EXMEM, exmem);
+
+ vmstate_register_ram_global(flash);
+ vmstate_register_ram_global(isram);
+ vmstate_register_ram_global(exmem);
+
+ memory_region_set_readonly(flash, true);
+
+ char const *firmware = NULL;
+ char const *filename;
+
+ 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);
+
+ sysbus_mmio_map(bus, 0, PHYS_BASE_IOREG);
+}
+
+static
+void sample_machine_init(MachineClass *mc)
+{
+ mc->desc = "sample";
+ mc->init = sample_init;
+ mc->is_default = 1;
+}
+
+DEFINE_MACHINE("sample", sample_machine_init)
diff --git a/include/disas/bfd.h b/include/disas/bfd.h
index a112e9c..04e2201 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
@@ -415,6 +421,7 @@ int print_insn_crisv10 (bfd_vma, disassemble_info*);
int print_insn_microblaze (bfd_vma, disassemble_info*);
int print_insn_ia64 (bfd_vma, disassemble_info*);
int print_insn_lm32 (bfd_vma, disassemble_info*);
+int print_insn_avr (bfd_vma, disassemble_info*);
#if 0
/* Fetch the disassembler for a given BFD, if that support is available. */
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..bbd2409
--- /dev/null
+++ b/target-avr/Makefile.objs
@@ -0,0 +1,5 @@
+obj-y += translate.o helper.o cpu.o
+obj-y += gdbstub.o
+obj-$(CONFIG_SOFTMMU) += machine.o
+
+obj-y += decode.o
diff --git a/target-avr/cpu-qom.h b/target-avr/cpu-qom.h
new file mode 100644
index 0000000..76ca908
--- /dev/null
+++ b/target-avr/cpu-qom.h
@@ -0,0 +1,97 @@
+/*
+ * 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 vmstate_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..5871693
--- /dev/null
+++ b/target-avr/cpu.c
@@ -0,0 +1,637 @@
+/*
+ * 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"
+#include "machine.h"
+
+static void avr_cpu_set_pc(
+ CPUState *cs,
+ vaddr value)
+{
+ AVRCPU *cpu = AVR_CPU(cs);
+
+ cpu->env.pc = value / 2;
+}
+
+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 = tb->pc / 2;
+}
+
+static void avr_cpu_reset(
+ CPUState *s)
+{
+ AVRCPU *cpu = AVR_CPU(s);
+ AVRCPUClass *mcc = AVR_CPU_GET_CLASS(cpu);
+ CPUAVRState *env = &cpu->env;
+ uint32_t features = env->features;
+
+ mcc->parent_reset(s);
+
+ memset(env, 0, sizeof(CPUAVRState));
+ env->pc = 0;
+ env->sregI = 1;
+ env->features = features;
+
+ tlb_flush(s, 1);
+}
+
+static void avr_cpu_disas_set_info(
+ CPUState *cpu,
+ disassemble_info *info)
+{
+ info->mach = bfd_arch_avr;
+ info->print_insn = print_insn_avr;
+}
+
+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 = &vmstate_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;
+}
+
+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);
+}
+
+static void avr_any_initfn(
+ Object *obj)
+{
+ /* Set cpu feature flags */
+}
+
+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},
+ { .name = "any", .initfn = avr_any_initfn },
+};
+
+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);
+ if (strcmp(name_a, "any-" TYPE_AVR_CPU) == 0) {
+ return 1;
+ } else if (strcmp(name_b, "any-" TYPE_AVR_CPU) == 0) {
+ return -1;
+ } else {
+ 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..2b67e89
--- /dev/null
+++ b/target-avr/cpu.h
@@ -0,0 +1,211 @@
+/*
+ * 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
+
+#define TARGET_IS_LIENDIAN 1
+
+#include "exec/cpu-defs.h"
+#include "fpu/softfloat.h"
+
+#define TARGET_PAGE_BITS 8
+#define TARGET_PHYS_ADDR_SPACE_BITS 24
+#define TARGET_VIRT_ADDR_SPACE_BITS 24
+#define NB_MMU_MODES 2
+
+#define CODE_INDEX 0
+#define DATA_INDEX 1
+
+#define EXCP_RESET 1
+#define EXCP_INT(n) (EXCP_RESET + (n) + 1)
+
+#define PHYS_ADDR_MASK 0xfff00000
+#define PHYS_CODE_BASE 0x00000000
+#define PHYS_DATA_BASE 0x00800000
+
+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 {
+ uint32_t pc; /* 22 bits */
+
+ uint32_t sregC; /* 1 bits */
+ uint32_t sregZ; /* 1 bits */
+ uint32_t sregN; /* 1 bits */
+ uint32_t sregV; /* 1 bits */
+ uint32_t sregS; /* 1 bits */
+ uint32_t sregH; /* 1 bits */
+ uint32_t sregT; /* 1 bits */
+ uint32_t sregI; /* 1 bits */
+
+ uint32_t rampD; /* 8 bits */
+ uint32_t rampX; /* 8 bits */
+ uint32_t rampY; /* 8 bits */
+ uint32_t rampZ; /* 8 bits */
+
+ uint32_t io[64]; /* 8 bits each */
+ uint32_t r[32]; /* 8 bits each */
+ uint32_t eind; /* 8 bits */
+ uint32_t sp; /* 8 bits */
+
+
+ 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 & (1UL << feature)) != 0;
+}
+
+static inline void avr_set_feature(
+ CPUAVRState *env,
+ int feature)
+{
+ env->features |= (1Ul << feature);
+}
+static inline void avr_del_feature(
+ CPUAVRState *env,
+ int feature)
+{
+ env->features &= ~(1Ul << feature);
+}
+
+#define cpu_list avr_cpu_list
+#define cpu_exec cpu_avr_exec
+#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 0;
+}
+
+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);
+
+#ifndef CONFIG_USER_ONLY
+QEMU_NORETURN void avr_cpu_unassigned_access(
+ CPUState *cpu,
+ hwaddr addr,
+ bool is_write,
+ bool is_exec,
+ int unused,
+ unsigned size);
+#endif
+
+static inline void cpu_get_tb_cpu_state(
+ CPUAVRState *env,
+ target_ulong *pc,
+ target_ulong *cs_base,
+ uint32_t *pflags)
+{
+ *pc = env->pc * 2;
+ *cs_base = 0;
+ *pflags = 0;
+}
+
+static inline int cpu_interrupts_enabled(
+ CPUAVRState *env1)
+{
+ return env1->sregI != 0;
+}
+
+#include "exec/exec-all.h"
+
+#endif /* !defined (__CPU_AVR_H__) */
diff --git a/target-avr/decode.c b/target-avr/decode.c
new file mode 100644
index 0000000..75a7036
--- /dev/null
+++ b/target-avr/decode.c
@@ -0,0 +1,740 @@
+/*
+ * 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 "decode.h"
+
+uint32_t get_opcode(
+ uint8_t const *code,
+ unsigned bitBase,
+ unsigned bitSsize);
+
+typedef int (*execute_function_t)(
+ CPUAVRState *env,
+ DisasContext *ctx,
+ uint8_t const *opcode);
+void avr_decode(
+ uint32_t pc,
+ uint32_t *length,
+ uint8_t const *code,
+ execute_function_t *execute);
+void avr_decode(
+ uint32_t pc,
+ uint32_t *length,
+ uint8_t const *code,
+ execute_function_t *execute)
+{
+ uint32_t opcode = get_opcode(code, 0, 16);
+ switch (opcode & 0x0000d000) {
+ case 0x00000000: {
+ uint32_t opcode = get_opcode(code, 0, 16);
+ switch (opcode & 0x00002c00) {
+ case 0x00000000: {
+ uint32_t opcode = get_opcode(code, 0, 16);
+ switch (opcode & 0x00000300) {
+ case 0x00000000: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_NOP_0000000000000000;
+ break;
+ }
+ case 0x00000100: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_MOVW_00000001aaaabbbb;
+ break;
+ }
+ case 0x00000200: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_MULS_00000010aaaabbbb;
+ break;
+ }
+ case 0x00000300: {
+ uint32_t opcode = get_opcode(code, 0, 16);
+ switch (opcode & 0x00000088) {
+ case 0x00000000: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_MULSU_000000110aaa0bbb;
+ break;
+ }
+ case 0x00000008: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_FMUL_000000110aaa1bbb;
+ break;
+ }
+ case 0x00000080: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_FMULS_000000111aaa0bbb;
+ break;
+ }
+ case 0x00000088: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_FMULSU_000000111aaa1bbb;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00000400: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_CPC_000001abbbbbcccc;
+ break;
+ }
+ case 0x00000800: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_SBC_000010abbbbbcccc;
+ break;
+ }
+ case 0x00000c00: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_ADD_000011abbbbbcccc;
+ break;
+ }
+ case 0x00002000: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_AND_001000abbbbbcccc;
+ break;
+ }
+ case 0x00002400: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_EOR_001001abbbbbcccc;
+ break;
+ }
+ case 0x00002800: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_OR_001010abbbbbcccc;
+ break;
+ }
+ case 0x00002c00: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_MOV_001011abbbbbcccc;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00001000: {
+ uint32_t opcode = get_opcode(code, 0, 16);
+ switch (opcode & 0x00002000) {
+ case 0x00000000: {
+ uint32_t opcode = get_opcode(code, 0, 16);
+ switch (opcode & 0x00000c00) {
+ case 0x00000000: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_CPSE_000100abbbbbcccc;
+ break;
+ }
+ case 0x00000400: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_CP_000101abbbbbcccc;
+ break;
+ }
+ case 0x00000800: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_SUB_000110abbbbbcccc;
+ break;
+ }
+ case 0x00000c00: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_ADC_000111abbbbbcccc;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00002000: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_CPI_0011aaaabbbbcccc;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00004000: {
+ uint32_t opcode = get_opcode(code, 0, 16);
+ switch (opcode & 0x00002000) {
+ case 0x00000000: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_SBCI_0100aaaabbbbcccc;
+ break;
+ }
+ case 0x00002000: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_ORI_0110aaaabbbbcccc;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00005000: {
+ uint32_t opcode = get_opcode(code, 0, 16);
+ switch (opcode & 0x00002000) {
+ case 0x00000000: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_SUBI_0101aaaabbbbcccc;
+ break;
+ }
+ case 0x00002000: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_ANDI_0111aaaabbbbcccc;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00008000: {
+ uint32_t opcode = get_opcode(code, 0, 16);
+ switch (opcode & 0x00000208) {
+ case 0x00000000: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_LDDZ_10a0bb0ccccc0ddd;
+ break;
+ }
+ case 0x00000008: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_LDDY_10a0bb0ccccc1ddd;
+ break;
+ }
+ case 0x00000200: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_STDZ_10a0bb1ccccc0ddd;
+ break;
+ }
+ case 0x00000208: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_STDY_10a0bb1ccccc1ddd;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00009000: {
+ uint32_t opcode = get_opcode(code, 0, 16);
+ switch (opcode & 0x00002800) {
+ case 0x00000000: {
+ uint32_t opcode = get_opcode(code, 0, 16);
+ switch (opcode & 0x00000600) {
+ case 0x00000000: {
+ uint32_t opcode = get_opcode(code, 0, 16);
+ switch (opcode & 0x0000000f) {
+ case 0x00000000: {
+ *length = 32;
+ *execute = (execute_function_t)&avr_execute_LDS_1001000aaaaa0000bbbbbbbbbbbbbbbb;
+ break;
+ }
+ case 0x00000001: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_LDZ2_1001000aaaaa0001;
+ break;
+ }
+ case 0x00000002: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_LDZ3_1001000aaaaa0010;
+ break;
+ }
+ case 0x00000003: {
+ break;
+ }
+ case 0x00000004: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_LPM2_1001000aaaaa0100;
+ break;
+ }
+ case 0x00000005: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_LPMX_1001000aaaaa0101;
+ break;
+ }
+ case 0x00000006: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_ELPM2_1001000aaaaa0110;
+ break;
+ }
+ case 0x00000007: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_ELPMX_1001000aaaaa0111;
+ break;
+ }
+ case 0x00000008: {
+ break;
+ }
+ case 0x00000009: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_LDY2_1001000aaaaa1001;
+ break;
+ }
+ case 0x0000000a: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_LDY3_1001000aaaaa1010;
+ break;
+ }
+ case 0x0000000b: {
+ break;
+ }
+ case 0x0000000c: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_LDX1_1001000aaaaa1100;
+ break;
+ }
+ case 0x0000000d: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_LDX2_1001000aaaaa1101;
+ break;
+ }
+ case 0x0000000e: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_LDX3_1001000aaaaa1110;
+ break;
+ }
+ case 0x0000000f: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_POP_1001000aaaaa1111;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00000200: {
+ uint32_t opcode = get_opcode(code, 0, 16);
+ switch (opcode & 0x0000000f) {
+ case 0x00000000: {
+ *length = 32;
+ *execute = (execute_function_t)&avr_execute_STS_1001001aaaaa0000bbbbbbbbbbbbbbbb;
+ break;
+ }
+ case 0x00000001: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_STZ2_1001001aaaaa0001;
+ break;
+ }
+ case 0x00000002: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_STZ3_1001001aaaaa0010;
+ break;
+ }
+ case 0x00000003: {
+ break;
+ }
+ case 0x00000004: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_XCH_1001001aaaaa0100;
+ break;
+ }
+ case 0x00000005: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_LAS_1001001aaaaa0101;
+ break;
+ }
+ case 0x00000006: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_LAC_1001001aaaaa0110;
+ break;
+ }
+ case 0x00000007: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_LAT_1001001aaaaa0111;
+ break;
+ }
+ case 0x00000008: {
+ break;
+ }
+ case 0x00000009: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_STY2_1001001aaaaa1001;
+ break;
+ }
+ case 0x0000000a: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_STY3_1001001aaaaa1010;
+ break;
+ }
+ case 0x0000000b: {
+ break;
+ }
+ case 0x0000000c: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_STX1_1001001aaaaa1100;
+ break;
+ }
+ case 0x0000000d: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_STX2_1001001aaaaa1101;
+ break;
+ }
+ case 0x0000000e: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_STX3_1001001aaaaa1110;
+ break;
+ }
+ case 0x0000000f: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_PUSH_1001001aaaaa1111;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00000400: {
+ uint32_t opcode = get_opcode(code, 0, 16);
+ switch (opcode & 0x0000000e) {
+ case 0x00000000: {
+ uint32_t opcode = get_opcode(code, 0, 16);
+ switch (opcode & 0x00000001) {
+ case 0x00000000: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_COM_1001010aaaaa0000;
+ break;
+ }
+ case 0x00000001: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_NEG_1001010aaaaa0001;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00000002: {
+ uint32_t opcode = get_opcode(code, 0, 16);
+ switch (opcode & 0x00000001) {
+ case 0x00000000: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_SWAP_1001010aaaaa0010;
+ break;
+ }
+ case 0x00000001: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_INC_1001010aaaaa0011;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00000004: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_ASR_1001010aaaaa0101;
+ break;
+ }
+ case 0x00000006: {
+ uint32_t opcode = get_opcode(code, 0, 16);
+ switch (opcode & 0x00000001) {
+ case 0x00000000: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_LSR_1001010aaaaa0110;
+ break;
+ }
+ case 0x00000001: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_ROR_1001010aaaaa0111;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00000008: {
+ uint32_t opcode = get_opcode(code, 0, 16);
+ switch (opcode & 0x00000181) {
+ case 0x00000000: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_BSET_100101000aaa1000;
+ break;
+ }
+ case 0x00000001: {
+ uint32_t opcode = get_opcode(code, 0, 16);
+ switch (opcode & 0x00000010) {
+ case 0x00000000: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_IJMP_1001010000001001;
+ break;
+ }
+ case 0x00000010: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_EIJMP_1001010000011001;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00000080: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_BCLR_100101001aaa1000;
+ break;
+ }
+ case 0x00000081: {
+ break;
+ }
+ case 0x00000100: {
+ uint32_t opcode = get_opcode(code, 0, 16);
+ switch (opcode & 0x00000010) {
+ case 0x00000000: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_RET_1001010100001000;
+ break;
+ }
+ case 0x00000010: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_RETI_1001010100011000;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00000101: {
+ uint32_t opcode = get_opcode(code, 0, 16);
+ switch (opcode & 0x00000010) {
+ case 0x00000000: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_ICALL_1001010100001001;
+ break;
+ }
+ case 0x00000010: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_EICALL_1001010100011001;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00000180: {
+ uint32_t opcode = get_opcode(code, 0, 16);
+ switch (opcode & 0x00000070) {
+ case 0x00000000: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_SLEEP_1001010110001000;
+ break;
+ }
+ case 0x00000010: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_BREAK_1001010110011000;
+ break;
+ }
+ case 0x00000020: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_WDR_1001010110101000;
+ break;
+ }
+ case 0x00000030: {
+ break;
+ }
+ case 0x00000040: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_LPM1_1001010111001000;
+ break;
+ }
+ case 0x00000050: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_ELPM1_1001010111011000;
+ break;
+ }
+ case 0x00000060: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_SPM_1001010111101000;
+ break;
+ }
+ case 0x00000070: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_SPMX_1001010111111000;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00000181: {
+ break;
+ }
+ }
+ break;
+ }
+ case 0x0000000a: {
+ uint32_t opcode = get_opcode(code, 0, 16);
+ switch (opcode & 0x00000001) {
+ case 0x00000000: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_DEC_1001010aaaaa1010;
+ break;
+ }
+ case 0x00000001: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_DES_10010100aaaa1011;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x0000000c: {
+ *length = 32;
+ *execute = (execute_function_t)&avr_execute_JMP_1001010aaaaa110bbbbbbbbbbbbbbbbb;
+ break;
+ }
+ case 0x0000000e: {
+ *length = 32;
+ *execute = (execute_function_t)&avr_execute_CALL_1001010aaaaa111bbbbbbbbbbbbbbbbb;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00000600: {
+ uint32_t opcode = get_opcode(code, 0, 16);
+ switch (opcode & 0x00000100) {
+ case 0x00000000: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_ADIW_10010110aabbcccc;
+ break;
+ }
+ case 0x00000100: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_SBIW_10010111aabbcccc;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00000800: {
+ uint32_t opcode = get_opcode(code, 0, 16);
+ switch (opcode & 0x00000400) {
+ case 0x00000000: {
+ uint32_t opcode = get_opcode(code, 0, 16);
+ switch (opcode & 0x00000300) {
+ case 0x00000000: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_CBI_10011000aaaaabbb;
+ break;
+ }
+ case 0x00000100: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_SBIC_10011001aaaaabbb;
+ break;
+ }
+ case 0x00000200: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_SBI_10011010aaaaabbb;
+ break;
+ }
+ case 0x00000300: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_SBIS_10011011aaaaabbb;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00000400: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_MUL_100111abbbbbcccc;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00002000: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_IN_10110aabbbbbcccc;
+ break;
+ }
+ case 0x00002800: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_OUT_10111aabbbbbcccc;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x0000c000: {
+ uint32_t opcode = get_opcode(code, 0, 16);
+ switch (opcode & 0x00002000) {
+ case 0x00000000: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_RJMP_1100aaaaaaaaaaaa;
+ break;
+ }
+ case 0x00002000: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_LDI_1110aaaabbbbcccc;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x0000d000: {
+ uint32_t opcode = get_opcode(code, 0, 16);
+ switch (opcode & 0x00002000) {
+ case 0x00000000: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_RCALL_1101aaaaaaaaaaaa;
+ break;
+ }
+ case 0x00002000: {
+ uint32_t opcode = get_opcode(code, 0, 16);
+ switch (opcode & 0x00000c00) {
+ case 0x00000000: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_BRBS_111100aaaaaaabbb;
+ break;
+ }
+ case 0x00000400: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_BRBC_111101aaaaaaabbb;
+ break;
+ }
+ case 0x00000800: {
+ uint32_t opcode = get_opcode(code, 0, 16);
+ switch (opcode & 0x00000200) {
+ case 0x00000000: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_BLD_1111100aaaaa0bbb;
+ break;
+ }
+ case 0x00000200: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_BST_1111101aaaaa0bbb;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00000c00: {
+ uint32_t opcode = get_opcode(code, 0, 16);
+ switch (opcode & 0x00000200) {
+ case 0x00000000: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_SBRC_1111110aaaaa0bbb;
+ break;
+ }
+ case 0x00000200: {
+ *length = 16;
+ *execute = (execute_function_t)&avr_execute_SBRS_1111111aaaaa0bbb;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+}
diff --git a/target-avr/decode.h b/target-avr/decode.h
new file mode 100644
index 0000000..c65cd32
--- /dev/null
+++ b/target-avr/decode.h
@@ -0,0 +1,1016 @@
+/*
+ * 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>
+ */
+
+typedef struct DisasContext DisasContext;
+typedef struct CPUAVRState CPUAVRState;
+
+typedef union avr_opcode_NOP_0000000000000000_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:16; /* 0000000000000000 */
+ };
+} avr_opcode_NOP_0000000000000000_t;
+int avr_execute_NOP_0000000000000000(CPUAVRState *env, DisasContext *ctx, avr_opcode_NOP_0000000000000000_t const *inst);
+
+typedef union avr_opcode_MOVW_00000001aaaabbbb_u {
+ uint16_t opcode;
+ struct {
+ uint16_t Rr:4;
+ uint16_t Rd:4;
+ uint16_t:8; /* 00000001 */
+ };
+} avr_opcode_MOVW_00000001aaaabbbb_t;
+int avr_execute_MOVW_00000001aaaabbbb(CPUAVRState *env, DisasContext *ctx, avr_opcode_MOVW_00000001aaaabbbb_t const *inst);
+
+typedef union avr_opcode_MULS_00000010aaaabbbb_u {
+ uint16_t opcode;
+ struct {
+ uint16_t Rr:4;
+ uint16_t Rd:4;
+ uint16_t:8; /* 00000010 */
+ };
+} avr_opcode_MULS_00000010aaaabbbb_t;
+int avr_execute_MULS_00000010aaaabbbb(CPUAVRState *env, DisasContext *ctx, avr_opcode_MULS_00000010aaaabbbb_t const *inst);
+
+typedef union avr_opcode_MULSU_000000110aaa0bbb_u {
+ uint16_t opcode;
+ struct {
+ uint16_t Rr:3;
+ uint16_t:1; /* 0 */
+ uint16_t Rd:3;
+ uint16_t:9; /* 000000110 */
+ };
+} avr_opcode_MULSU_000000110aaa0bbb_t;
+int avr_execute_MULSU_000000110aaa0bbb(CPUAVRState *env, DisasContext *ctx, avr_opcode_MULSU_000000110aaa0bbb_t const *inst);
+
+typedef union avr_opcode_FMUL_000000110aaa1bbb_u {
+ uint16_t opcode;
+ struct {
+ uint16_t Rr:3;
+ uint16_t:1; /* 1 */
+ uint16_t Rd:3;
+ uint16_t:9; /* 000000110 */
+ };
+} avr_opcode_FMUL_000000110aaa1bbb_t;
+int avr_execute_FMUL_000000110aaa1bbb(CPUAVRState *env, DisasContext *ctx, avr_opcode_FMUL_000000110aaa1bbb_t const *inst);
+
+typedef union avr_opcode_FMULS_000000111aaa0bbb_u {
+ uint16_t opcode;
+ struct {
+ uint16_t Rr:3;
+ uint16_t:1; /* 0 */
+ uint16_t Rd:3;
+ uint16_t:9; /* 000000111 */
+ };
+} avr_opcode_FMULS_000000111aaa0bbb_t;
+int avr_execute_FMULS_000000111aaa0bbb(CPUAVRState *env, DisasContext *ctx, avr_opcode_FMULS_000000111aaa0bbb_t const *inst);
+
+typedef union avr_opcode_FMULSU_000000111aaa1bbb_u {
+ uint16_t opcode;
+ struct {
+ uint16_t Rr:3;
+ uint16_t:1; /* 1 */
+ uint16_t Rd:3;
+ uint16_t:9; /* 000000111 */
+ };
+} avr_opcode_FMULSU_000000111aaa1bbb_t;
+int avr_execute_FMULSU_000000111aaa1bbb(CPUAVRState *env, DisasContext *ctx, avr_opcode_FMULSU_000000111aaa1bbb_t const *inst);
+
+typedef union avr_opcode_CPC_000001abbbbbcccc_u {
+ uint16_t opcode;
+ struct {
+ uint16_t lRr:4;
+ uint16_t Rd:5;
+ uint16_t hRr:1;
+ uint16_t:6; /* 000001 */
+ };
+} avr_opcode_CPC_000001abbbbbcccc_t;
+int avr_execute_CPC_000001abbbbbcccc(CPUAVRState *env, DisasContext *ctx, avr_opcode_CPC_000001abbbbbcccc_t const *inst);
+
+typedef union avr_opcode_SBC_000010abbbbbcccc_u {
+ uint16_t opcode;
+ struct {
+ uint16_t lRr:4;
+ uint16_t Rd:5;
+ uint16_t hRr:1;
+ uint16_t:6; /* 000010 */
+ };
+} avr_opcode_SBC_000010abbbbbcccc_t;
+int avr_execute_SBC_000010abbbbbcccc(CPUAVRState *env, DisasContext *ctx, avr_opcode_SBC_000010abbbbbcccc_t const *inst);
+
+typedef union avr_opcode_ADD_000011abbbbbcccc_u {
+ uint16_t opcode;
+ struct {
+ uint16_t lRr:4;
+ uint16_t Rd:5;
+ uint16_t hRr:1;
+ uint16_t:6; /* 000011 */
+ };
+} avr_opcode_ADD_000011abbbbbcccc_t;
+int avr_execute_ADD_000011abbbbbcccc(CPUAVRState *env, DisasContext *ctx, avr_opcode_ADD_000011abbbbbcccc_t const *inst);
+
+typedef union avr_opcode_AND_001000abbbbbcccc_u {
+ uint16_t opcode;
+ struct {
+ uint16_t lRr:4;
+ uint16_t Rd:5;
+ uint16_t hRr:1;
+ uint16_t:6; /* 001000 */
+ };
+} avr_opcode_AND_001000abbbbbcccc_t;
+int avr_execute_AND_001000abbbbbcccc(CPUAVRState *env, DisasContext *ctx, avr_opcode_AND_001000abbbbbcccc_t const *inst);
+
+typedef union avr_opcode_EOR_001001abbbbbcccc_u {
+ uint16_t opcode;
+ struct {
+ uint16_t lRr:4;
+ uint16_t Rd:5;
+ uint16_t hRr:1;
+ uint16_t:6; /* 001001 */
+ };
+} avr_opcode_EOR_001001abbbbbcccc_t;
+int avr_execute_EOR_001001abbbbbcccc(CPUAVRState *env, DisasContext *ctx, avr_opcode_EOR_001001abbbbbcccc_t const *inst);
+
+typedef union avr_opcode_OR_001010abbbbbcccc_u {
+ uint16_t opcode;
+ struct {
+ uint16_t lRr:4;
+ uint16_t Rd:5;
+ uint16_t hRr:1;
+ uint16_t:6; /* 001010 */
+ };
+} avr_opcode_OR_001010abbbbbcccc_t;
+int avr_execute_OR_001010abbbbbcccc(CPUAVRState *env, DisasContext *ctx, avr_opcode_OR_001010abbbbbcccc_t const *inst);
+
+typedef union avr_opcode_MOV_001011abbbbbcccc_u {
+ uint16_t opcode;
+ struct {
+ uint16_t lRr:4;
+ uint16_t Rd:5;
+ uint16_t hRr:1;
+ uint16_t:6; /* 001011 */
+ };
+} avr_opcode_MOV_001011abbbbbcccc_t;
+int avr_execute_MOV_001011abbbbbcccc(CPUAVRState *env, DisasContext *ctx, avr_opcode_MOV_001011abbbbbcccc_t const *inst);
+
+typedef union avr_opcode_CPSE_000100abbbbbcccc_u {
+ uint16_t opcode;
+ struct {
+ uint16_t lRr:4;
+ uint16_t Rd:5;
+ uint16_t hRr:1;
+ uint16_t:6; /* 000100 */
+ };
+} avr_opcode_CPSE_000100abbbbbcccc_t;
+int avr_execute_CPSE_000100abbbbbcccc(CPUAVRState *env, DisasContext *ctx, avr_opcode_CPSE_000100abbbbbcccc_t const *inst);
+
+typedef union avr_opcode_CP_000101abbbbbcccc_u {
+ uint16_t opcode;
+ struct {
+ uint16_t lRr:4;
+ uint16_t Rd:5;
+ uint16_t hRr:1;
+ uint16_t:6; /* 000101 */
+ };
+} avr_opcode_CP_000101abbbbbcccc_t;
+int avr_execute_CP_000101abbbbbcccc(CPUAVRState *env, DisasContext *ctx, avr_opcode_CP_000101abbbbbcccc_t const *inst);
+
+typedef union avr_opcode_SUB_000110abbbbbcccc_u {
+ uint16_t opcode;
+ struct {
+ uint16_t lRr:4;
+ uint16_t Rd:5;
+ uint16_t hRr:1;
+ uint16_t:6; /* 000110 */
+ };
+} avr_opcode_SUB_000110abbbbbcccc_t;
+int avr_execute_SUB_000110abbbbbcccc(CPUAVRState *env, DisasContext *ctx, avr_opcode_SUB_000110abbbbbcccc_t const *inst);
+
+typedef union avr_opcode_ADC_000111abbbbbcccc_u {
+ uint16_t opcode;
+ struct {
+ uint16_t lRr:4;
+ uint16_t Rd:5;
+ uint16_t hRr:1;
+ uint16_t:6; /* 000111 */
+ };
+} avr_opcode_ADC_000111abbbbbcccc_t;
+int avr_execute_ADC_000111abbbbbcccc(CPUAVRState *env, DisasContext *ctx, avr_opcode_ADC_000111abbbbbcccc_t const *inst);
+
+typedef union avr_opcode_CPI_0011aaaabbbbcccc_u {
+ uint16_t opcode;
+ struct {
+ uint16_t lImm:4;
+ uint16_t Rd:4;
+ uint16_t hImm:4;
+ uint16_t:4; /* 0011 */
+ };
+} avr_opcode_CPI_0011aaaabbbbcccc_t;
+int avr_execute_CPI_0011aaaabbbbcccc(CPUAVRState *env, DisasContext *ctx, avr_opcode_CPI_0011aaaabbbbcccc_t const *inst);
+
+typedef union avr_opcode_SBCI_0100aaaabbbbcccc_u {
+ uint16_t opcode;
+ struct {
+ uint16_t lImm:4;
+ uint16_t Rd:4;
+ uint16_t hImm:4;
+ uint16_t:4; /* 0100 */
+ };
+} avr_opcode_SBCI_0100aaaabbbbcccc_t;
+int avr_execute_SBCI_0100aaaabbbbcccc(CPUAVRState *env, DisasContext *ctx, avr_opcode_SBCI_0100aaaabbbbcccc_t const *inst);
+
+typedef union avr_opcode_ORI_0110aaaabbbbcccc_u {
+ uint16_t opcode;
+ struct {
+ uint16_t lImm:4;
+ uint16_t Rd:4;
+ uint16_t hImm:4;
+ uint16_t:4; /* 0110 */
+ };
+} avr_opcode_ORI_0110aaaabbbbcccc_t;
+int avr_execute_ORI_0110aaaabbbbcccc(CPUAVRState *env, DisasContext *ctx, avr_opcode_ORI_0110aaaabbbbcccc_t const *inst);
+
+typedef union avr_opcode_SUBI_0101aaaabbbbcccc_u {
+ uint16_t opcode;
+ struct {
+ uint16_t lImm:4;
+ uint16_t Rd:4;
+ uint16_t hImm:4;
+ uint16_t:4; /* 0101 */
+ };
+} avr_opcode_SUBI_0101aaaabbbbcccc_t;
+int avr_execute_SUBI_0101aaaabbbbcccc(CPUAVRState *env, DisasContext *ctx, avr_opcode_SUBI_0101aaaabbbbcccc_t const *inst);
+
+typedef union avr_opcode_ANDI_0111aaaabbbbcccc_u {
+ uint16_t opcode;
+ struct {
+ uint16_t lImm:4;
+ uint16_t Rd:4;
+ uint16_t hImm:4;
+ uint16_t:4; /* 0111 */
+ };
+} avr_opcode_ANDI_0111aaaabbbbcccc_t;
+int avr_execute_ANDI_0111aaaabbbbcccc(CPUAVRState *env, DisasContext *ctx, avr_opcode_ANDI_0111aaaabbbbcccc_t const *inst);
+
+typedef union avr_opcode_LDDZ_10a0bb0ccccc0ddd_u {
+ uint16_t opcode;
+ struct {
+ uint16_t lImm:3;
+ uint16_t:1; /* 0 */
+ uint16_t Rd:5;
+ uint16_t:1; /* 0 */
+ uint16_t mImm:2;
+ uint16_t:1; /* 0 */
+ uint16_t hImm:1;
+ uint16_t:2; /* 10 */
+ };
+} avr_opcode_LDDZ_10a0bb0ccccc0ddd_t;
+int avr_execute_LDDZ_10a0bb0ccccc0ddd(CPUAVRState *env, DisasContext *ctx, avr_opcode_LDDZ_10a0bb0ccccc0ddd_t const *inst);
+
+typedef union avr_opcode_LDDY_10a0bb0ccccc1ddd_u {
+ uint16_t opcode;
+ struct {
+ uint16_t lImm:3;
+ uint16_t:1; /* 1 */
+ uint16_t Rd:5;
+ uint16_t:1; /* 0 */
+ uint16_t mImm:2;
+ uint16_t:1; /* 0 */
+ uint16_t hImm:1;
+ uint16_t:2; /* 10 */
+ };
+} avr_opcode_LDDY_10a0bb0ccccc1ddd_t;
+int avr_execute_LDDY_10a0bb0ccccc1ddd(CPUAVRState *env, DisasContext *ctx, avr_opcode_LDDY_10a0bb0ccccc1ddd_t const *inst);
+
+typedef union avr_opcode_STDZ_10a0bb1ccccc0ddd_u {
+ uint16_t opcode;
+ struct {
+ uint16_t lImm:3;
+ uint16_t:1; /* 0 */
+ uint16_t Rd:5;
+ uint16_t:1; /* 1 */
+ uint16_t mImm:2;
+ uint16_t:1; /* 0 */
+ uint16_t hImm:1;
+ uint16_t:2; /* 10 */
+ };
+} avr_opcode_STDZ_10a0bb1ccccc0ddd_t;
+int avr_execute_STDZ_10a0bb1ccccc0ddd(CPUAVRState *env, DisasContext *ctx, avr_opcode_STDZ_10a0bb1ccccc0ddd_t const *inst);
+
+typedef union avr_opcode_STDY_10a0bb1ccccc1ddd_u {
+ uint16_t opcode;
+ struct {
+ uint16_t lImm:3;
+ uint16_t:1; /* 1 */
+ uint16_t Rd:5;
+ uint16_t:1; /* 1 */
+ uint16_t mImm:2;
+ uint16_t:1; /* 0 */
+ uint16_t hImm:1;
+ uint16_t:2; /* 10 */
+ };
+} avr_opcode_STDY_10a0bb1ccccc1ddd_t;
+int avr_execute_STDY_10a0bb1ccccc1ddd(CPUAVRState *env, DisasContext *ctx, avr_opcode_STDY_10a0bb1ccccc1ddd_t const *inst);
+
+typedef union avr_opcode_LDS_1001000aaaaa0000bbbbbbbbbbbbbbbb_u {
+ uint32_t opcode;
+ struct {
+ uint32_t Imm:16;
+ uint32_t:4; /* 0000 */
+ uint32_t Rd:5;
+ uint32_t:7; /* 1001000 */
+ };
+} avr_opcode_LDS_1001000aaaaa0000bbbbbbbbbbbbbbbb_t;
+int avr_execute_LDS_1001000aaaaa0000bbbbbbbbbbbbbbbb(CPUAVRState *env, DisasContext *ctx, avr_opcode_LDS_1001000aaaaa0000bbbbbbbbbbbbbbbb_t const *inst);
+
+typedef union avr_opcode_LDZ2_1001000aaaaa0001_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:4; /* 0001 */
+ uint16_t Rd:5;
+ uint16_t:7; /* 1001000 */
+ };
+} avr_opcode_LDZ2_1001000aaaaa0001_t;
+int avr_execute_LDZ2_1001000aaaaa0001(CPUAVRState *env, DisasContext *ctx, avr_opcode_LDZ2_1001000aaaaa0001_t const *inst);
+
+typedef union avr_opcode_LDZ3_1001000aaaaa0010_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:4; /* 0010 */
+ uint16_t Rd:5;
+ uint16_t:7; /* 1001000 */
+ };
+} avr_opcode_LDZ3_1001000aaaaa0010_t;
+int avr_execute_LDZ3_1001000aaaaa0010(CPUAVRState *env, DisasContext *ctx, avr_opcode_LDZ3_1001000aaaaa0010_t const *inst);
+
+typedef union avr_opcode_LPM2_1001000aaaaa0100_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:4; /* 0100 */
+ uint16_t Rd:5;
+ uint16_t:7; /* 1001000 */
+ };
+} avr_opcode_LPM2_1001000aaaaa0100_t;
+int avr_execute_LPM2_1001000aaaaa0100(CPUAVRState *env, DisasContext *ctx, avr_opcode_LPM2_1001000aaaaa0100_t const *inst);
+
+typedef union avr_opcode_LPMX_1001000aaaaa0101_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:4; /* 0101 */
+ uint16_t Rd:5;
+ uint16_t:7; /* 1001000 */
+ };
+} avr_opcode_LPMX_1001000aaaaa0101_t;
+int avr_execute_LPMX_1001000aaaaa0101(CPUAVRState *env, DisasContext *ctx, avr_opcode_LPMX_1001000aaaaa0101_t const *inst);
+
+typedef union avr_opcode_ELPM2_1001000aaaaa0110_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:4; /* 0110 */
+ uint16_t Rd:5;
+ uint16_t:7; /* 1001000 */
+ };
+} avr_opcode_ELPM2_1001000aaaaa0110_t;
+int avr_execute_ELPM2_1001000aaaaa0110(CPUAVRState *env, DisasContext *ctx, avr_opcode_ELPM2_1001000aaaaa0110_t const *inst);
+
+typedef union avr_opcode_ELPMX_1001000aaaaa0111_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:4; /* 0111 */
+ uint16_t Rd:5;
+ uint16_t:7; /* 1001000 */
+ };
+} avr_opcode_ELPMX_1001000aaaaa0111_t;
+int avr_execute_ELPMX_1001000aaaaa0111(CPUAVRState *env, DisasContext *ctx, avr_opcode_ELPMX_1001000aaaaa0111_t const *inst);
+
+typedef union avr_opcode_LDY2_1001000aaaaa1001_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:4; /* 1001 */
+ uint16_t Rd:5;
+ uint16_t:7; /* 1001000 */
+ };
+} avr_opcode_LDY2_1001000aaaaa1001_t;
+int avr_execute_LDY2_1001000aaaaa1001(CPUAVRState *env, DisasContext *ctx, avr_opcode_LDY2_1001000aaaaa1001_t const *inst);
+
+typedef union avr_opcode_LDY3_1001000aaaaa1010_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:4; /* 1010 */
+ uint16_t Rd:5;
+ uint16_t:7; /* 1001000 */
+ };
+} avr_opcode_LDY3_1001000aaaaa1010_t;
+int avr_execute_LDY3_1001000aaaaa1010(CPUAVRState *env, DisasContext *ctx, avr_opcode_LDY3_1001000aaaaa1010_t const *inst);
+
+typedef union avr_opcode_LDX1_1001000aaaaa1100_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:4; /* 1100 */
+ uint16_t Rd:5;
+ uint16_t:7; /* 1001000 */
+ };
+} avr_opcode_LDX1_1001000aaaaa1100_t;
+int avr_execute_LDX1_1001000aaaaa1100(CPUAVRState *env, DisasContext *ctx, avr_opcode_LDX1_1001000aaaaa1100_t const *inst);
+
+typedef union avr_opcode_LDX2_1001000aaaaa1101_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:4; /* 1101 */
+ uint16_t Rd:5;
+ uint16_t:7; /* 1001000 */
+ };
+} avr_opcode_LDX2_1001000aaaaa1101_t;
+int avr_execute_LDX2_1001000aaaaa1101(CPUAVRState *env, DisasContext *ctx, avr_opcode_LDX2_1001000aaaaa1101_t const *inst);
+
+typedef union avr_opcode_LDX3_1001000aaaaa1110_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:4; /* 1110 */
+ uint16_t Rd:5;
+ uint16_t:7; /* 1001000 */
+ };
+} avr_opcode_LDX3_1001000aaaaa1110_t;
+int avr_execute_LDX3_1001000aaaaa1110(CPUAVRState *env, DisasContext *ctx, avr_opcode_LDX3_1001000aaaaa1110_t const *inst);
+
+typedef union avr_opcode_POP_1001000aaaaa1111_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:4; /* 1111 */
+ uint16_t Rd:5;
+ uint16_t:7; /* 1001000 */
+ };
+} avr_opcode_POP_1001000aaaaa1111_t;
+int avr_execute_POP_1001000aaaaa1111(CPUAVRState *env, DisasContext *ctx, avr_opcode_POP_1001000aaaaa1111_t const *inst);
+
+typedef union avr_opcode_STS_1001001aaaaa0000bbbbbbbbbbbbbbbb_u {
+ uint32_t opcode;
+ struct {
+ uint32_t Imm:16;
+ uint32_t:4; /* 0000 */
+ uint32_t Rd:5;
+ uint32_t:7; /* 1001001 */
+ };
+} avr_opcode_STS_1001001aaaaa0000bbbbbbbbbbbbbbbb_t;
+int avr_execute_STS_1001001aaaaa0000bbbbbbbbbbbbbbbb(CPUAVRState *env, DisasContext *ctx, avr_opcode_STS_1001001aaaaa0000bbbbbbbbbbbbbbbb_t const *inst);
+
+typedef union avr_opcode_STZ2_1001001aaaaa0001_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:4; /* 0001 */
+ uint16_t Rd:5;
+ uint16_t:7; /* 1001001 */
+ };
+} avr_opcode_STZ2_1001001aaaaa0001_t;
+int avr_execute_STZ2_1001001aaaaa0001(CPUAVRState *env, DisasContext *ctx, avr_opcode_STZ2_1001001aaaaa0001_t const *inst);
+
+typedef union avr_opcode_STZ3_1001001aaaaa0010_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:4; /* 0010 */
+ uint16_t Rd:5;
+ uint16_t:7; /* 1001001 */
+ };
+} avr_opcode_STZ3_1001001aaaaa0010_t;
+int avr_execute_STZ3_1001001aaaaa0010(CPUAVRState *env, DisasContext *ctx, avr_opcode_STZ3_1001001aaaaa0010_t const *inst);
+
+typedef union avr_opcode_XCH_1001001aaaaa0100_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:4; /* 0100 */
+ uint16_t Rd:5;
+ uint16_t:7; /* 1001001 */
+ };
+} avr_opcode_XCH_1001001aaaaa0100_t;
+int avr_execute_XCH_1001001aaaaa0100(CPUAVRState *env, DisasContext *ctx, avr_opcode_XCH_1001001aaaaa0100_t const *inst);
+
+typedef union avr_opcode_LAS_1001001aaaaa0101_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:4; /* 0101 */
+ uint16_t Rr:5;
+ uint16_t:7; /* 1001001 */
+ };
+} avr_opcode_LAS_1001001aaaaa0101_t;
+int avr_execute_LAS_1001001aaaaa0101(CPUAVRState *env, DisasContext *ctx, avr_opcode_LAS_1001001aaaaa0101_t const *inst);
+
+typedef union avr_opcode_LAC_1001001aaaaa0110_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:4; /* 0110 */
+ uint16_t Rr:5;
+ uint16_t:7; /* 1001001 */
+ };
+} avr_opcode_LAC_1001001aaaaa0110_t;
+int avr_execute_LAC_1001001aaaaa0110(CPUAVRState *env, DisasContext *ctx, avr_opcode_LAC_1001001aaaaa0110_t const *inst);
+
+typedef union avr_opcode_LAT_1001001aaaaa0111_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:4; /* 0111 */
+ uint16_t Rr:5;
+ uint16_t:7; /* 1001001 */
+ };
+} avr_opcode_LAT_1001001aaaaa0111_t;
+int avr_execute_LAT_1001001aaaaa0111(CPUAVRState *env, DisasContext *ctx, avr_opcode_LAT_1001001aaaaa0111_t const *inst);
+
+typedef union avr_opcode_STY2_1001001aaaaa1001_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:4; /* 1001 */
+ uint16_t Rd:5;
+ uint16_t:7; /* 1001001 */
+ };
+} avr_opcode_STY2_1001001aaaaa1001_t;
+int avr_execute_STY2_1001001aaaaa1001(CPUAVRState *env, DisasContext *ctx, avr_opcode_STY2_1001001aaaaa1001_t const *inst);
+
+typedef union avr_opcode_STY3_1001001aaaaa1010_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:4; /* 1010 */
+ uint16_t Rd:5;
+ uint16_t:7; /* 1001001 */
+ };
+} avr_opcode_STY3_1001001aaaaa1010_t;
+int avr_execute_STY3_1001001aaaaa1010(CPUAVRState *env, DisasContext *ctx, avr_opcode_STY3_1001001aaaaa1010_t const *inst);
+
+typedef union avr_opcode_STX1_1001001aaaaa1100_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:4; /* 1100 */
+ uint16_t Rr:5;
+ uint16_t:7; /* 1001001 */
+ };
+} avr_opcode_STX1_1001001aaaaa1100_t;
+int avr_execute_STX1_1001001aaaaa1100(CPUAVRState *env, DisasContext *ctx, avr_opcode_STX1_1001001aaaaa1100_t const *inst);
+
+typedef union avr_opcode_STX2_1001001aaaaa1101_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:4; /* 1101 */
+ uint16_t Rr:5;
+ uint16_t:7; /* 1001001 */
+ };
+} avr_opcode_STX2_1001001aaaaa1101_t;
+int avr_execute_STX2_1001001aaaaa1101(CPUAVRState *env, DisasContext *ctx, avr_opcode_STX2_1001001aaaaa1101_t const *inst);
+
+typedef union avr_opcode_STX3_1001001aaaaa1110_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:4; /* 1110 */
+ uint16_t Rr:5;
+ uint16_t:7; /* 1001001 */
+ };
+} avr_opcode_STX3_1001001aaaaa1110_t;
+int avr_execute_STX3_1001001aaaaa1110(CPUAVRState *env, DisasContext *ctx, avr_opcode_STX3_1001001aaaaa1110_t const *inst);
+
+typedef union avr_opcode_PUSH_1001001aaaaa1111_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:4; /* 1111 */
+ uint16_t Rd:5;
+ uint16_t:7; /* 1001001 */
+ };
+} avr_opcode_PUSH_1001001aaaaa1111_t;
+int avr_execute_PUSH_1001001aaaaa1111(CPUAVRState *env, DisasContext *ctx, avr_opcode_PUSH_1001001aaaaa1111_t const *inst);
+
+typedef union avr_opcode_COM_1001010aaaaa0000_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:4; /* 0000 */
+ uint16_t Rd:5;
+ uint16_t:7; /* 1001010 */
+ };
+} avr_opcode_COM_1001010aaaaa0000_t;
+int avr_execute_COM_1001010aaaaa0000(CPUAVRState *env, DisasContext *ctx, avr_opcode_COM_1001010aaaaa0000_t const *inst);
+
+typedef union avr_opcode_NEG_1001010aaaaa0001_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:4; /* 0001 */
+ uint16_t Rd:5;
+ uint16_t:7; /* 1001010 */
+ };
+} avr_opcode_NEG_1001010aaaaa0001_t;
+int avr_execute_NEG_1001010aaaaa0001(CPUAVRState *env, DisasContext *ctx, avr_opcode_NEG_1001010aaaaa0001_t const *inst);
+
+typedef union avr_opcode_SWAP_1001010aaaaa0010_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:4; /* 0010 */
+ uint16_t Rd:5;
+ uint16_t:7; /* 1001010 */
+ };
+} avr_opcode_SWAP_1001010aaaaa0010_t;
+int avr_execute_SWAP_1001010aaaaa0010(CPUAVRState *env, DisasContext *ctx, avr_opcode_SWAP_1001010aaaaa0010_t const *inst);
+
+typedef union avr_opcode_INC_1001010aaaaa0011_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:4; /* 0011 */
+ uint16_t Rd:5;
+ uint16_t:7; /* 1001010 */
+ };
+} avr_opcode_INC_1001010aaaaa0011_t;
+int avr_execute_INC_1001010aaaaa0011(CPUAVRState *env, DisasContext *ctx, avr_opcode_INC_1001010aaaaa0011_t const *inst);
+
+typedef union avr_opcode_ASR_1001010aaaaa0101_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:4; /* 0101 */
+ uint16_t Rd:5;
+ uint16_t:7; /* 1001010 */
+ };
+} avr_opcode_ASR_1001010aaaaa0101_t;
+int avr_execute_ASR_1001010aaaaa0101(CPUAVRState *env, DisasContext *ctx, avr_opcode_ASR_1001010aaaaa0101_t const *inst);
+
+typedef union avr_opcode_LSR_1001010aaaaa0110_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:4; /* 0110 */
+ uint16_t Rd:5;
+ uint16_t:7; /* 1001010 */
+ };
+} avr_opcode_LSR_1001010aaaaa0110_t;
+int avr_execute_LSR_1001010aaaaa0110(CPUAVRState *env, DisasContext *ctx, avr_opcode_LSR_1001010aaaaa0110_t const *inst);
+
+typedef union avr_opcode_ROR_1001010aaaaa0111_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:4; /* 0111 */
+ uint16_t Rd:5;
+ uint16_t:7; /* 1001010 */
+ };
+} avr_opcode_ROR_1001010aaaaa0111_t;
+int avr_execute_ROR_1001010aaaaa0111(CPUAVRState *env, DisasContext *ctx, avr_opcode_ROR_1001010aaaaa0111_t const *inst);
+
+typedef union avr_opcode_BSET_100101000aaa1000_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:4; /* 1000 */
+ uint16_t Bit:3;
+ uint16_t:9; /* 100101000 */
+ };
+} avr_opcode_BSET_100101000aaa1000_t;
+int avr_execute_BSET_100101000aaa1000(CPUAVRState *env, DisasContext *ctx, avr_opcode_BSET_100101000aaa1000_t const *inst);
+
+typedef union avr_opcode_IJMP_1001010000001001_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:16; /* 1001010000001001 */
+ };
+} avr_opcode_IJMP_1001010000001001_t;
+int avr_execute_IJMP_1001010000001001(CPUAVRState *env, DisasContext *ctx, avr_opcode_IJMP_1001010000001001_t const *inst);
+
+typedef union avr_opcode_EIJMP_1001010000011001_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:16; /* 1001010000011001 */
+ };
+} avr_opcode_EIJMP_1001010000011001_t;
+int avr_execute_EIJMP_1001010000011001(CPUAVRState *env, DisasContext *ctx, avr_opcode_EIJMP_1001010000011001_t const *inst);
+
+typedef union avr_opcode_BCLR_100101001aaa1000_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:4; /* 1000 */
+ uint16_t Bit:3;
+ uint16_t:9; /* 100101001 */
+ };
+} avr_opcode_BCLR_100101001aaa1000_t;
+int avr_execute_BCLR_100101001aaa1000(CPUAVRState *env, DisasContext *ctx, avr_opcode_BCLR_100101001aaa1000_t const *inst);
+
+typedef union avr_opcode_RET_1001010100001000_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:16; /* 1001010100001000 */
+ };
+} avr_opcode_RET_1001010100001000_t;
+int avr_execute_RET_1001010100001000(CPUAVRState *env, DisasContext *ctx, avr_opcode_RET_1001010100001000_t const *inst);
+
+typedef union avr_opcode_RETI_1001010100011000_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:16; /* 1001010100011000 */
+ };
+} avr_opcode_RETI_1001010100011000_t;
+int avr_execute_RETI_1001010100011000(CPUAVRState *env, DisasContext *ctx, avr_opcode_RETI_1001010100011000_t const *inst);
+
+typedef union avr_opcode_ICALL_1001010100001001_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:16; /* 1001010100001001 */
+ };
+} avr_opcode_ICALL_1001010100001001_t;
+int avr_execute_ICALL_1001010100001001(CPUAVRState *env, DisasContext *ctx, avr_opcode_ICALL_1001010100001001_t const *inst);
+
+typedef union avr_opcode_EICALL_1001010100011001_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:16; /* 1001010100011001 */
+ };
+} avr_opcode_EICALL_1001010100011001_t;
+int avr_execute_EICALL_1001010100011001(CPUAVRState *env, DisasContext *ctx, avr_opcode_EICALL_1001010100011001_t const *inst);
+
+typedef union avr_opcode_SLEEP_1001010110001000_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:16; /* 1001010110001000 */
+ };
+} avr_opcode_SLEEP_1001010110001000_t;
+int avr_execute_SLEEP_1001010110001000(CPUAVRState *env, DisasContext *ctx, avr_opcode_SLEEP_1001010110001000_t const *inst);
+
+typedef union avr_opcode_BREAK_1001010110011000_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:16; /* 1001010110011000 */
+ };
+} avr_opcode_BREAK_1001010110011000_t;
+int avr_execute_BREAK_1001010110011000(CPUAVRState *env, DisasContext *ctx, avr_opcode_BREAK_1001010110011000_t const *inst);
+
+typedef union avr_opcode_WDR_1001010110101000_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:16; /* 1001010110101000 */
+ };
+} avr_opcode_WDR_1001010110101000_t;
+int avr_execute_WDR_1001010110101000(CPUAVRState *env, DisasContext *ctx, avr_opcode_WDR_1001010110101000_t const *inst);
+
+typedef union avr_opcode_LPM1_1001010111001000_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:16; /* 1001010111001000 */
+ };
+} avr_opcode_LPM1_1001010111001000_t;
+int avr_execute_LPM1_1001010111001000(CPUAVRState *env, DisasContext *ctx, avr_opcode_LPM1_1001010111001000_t const *inst);
+
+typedef union avr_opcode_ELPM1_1001010111011000_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:16; /* 1001010111011000 */
+ };
+} avr_opcode_ELPM1_1001010111011000_t;
+int avr_execute_ELPM1_1001010111011000(CPUAVRState *env, DisasContext *ctx, avr_opcode_ELPM1_1001010111011000_t const *inst);
+
+typedef union avr_opcode_SPM_1001010111101000_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:16; /* 1001010111101000 */
+ };
+} avr_opcode_SPM_1001010111101000_t;
+int avr_execute_SPM_1001010111101000(CPUAVRState *env, DisasContext *ctx, avr_opcode_SPM_1001010111101000_t const *inst);
+
+typedef union avr_opcode_SPMX_1001010111111000_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:16; /* 1001010111111000 */
+ };
+} avr_opcode_SPMX_1001010111111000_t;
+int avr_execute_SPMX_1001010111111000(CPUAVRState *env, DisasContext *ctx, avr_opcode_SPMX_1001010111111000_t const *inst);
+
+typedef union avr_opcode_DEC_1001010aaaaa1010_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:4; /* 1010 */
+ uint16_t Rd:5;
+ uint16_t:7; /* 1001010 */
+ };
+} avr_opcode_DEC_1001010aaaaa1010_t;
+int avr_execute_DEC_1001010aaaaa1010(CPUAVRState *env, DisasContext *ctx, avr_opcode_DEC_1001010aaaaa1010_t const *inst);
+
+typedef union avr_opcode_DES_10010100aaaa1011_u {
+ uint16_t opcode;
+ struct {
+ uint16_t:4; /* 1011 */
+ uint16_t Imm:4;
+ uint16_t:8; /* 10010100 */
+ };
+} avr_opcode_DES_10010100aaaa1011_t;
+int avr_execute_DES_10010100aaaa1011(CPUAVRState *env, DisasContext *ctx, avr_opcode_DES_10010100aaaa1011_t const *inst);
+
+typedef union avr_opcode_JMP_1001010aaaaa110bbbbbbbbbbbbbbbbb_u {
+ uint32_t opcode;
+ struct {
+ uint32_t lImm:17;
+ uint32_t:3; /* 110 */
+ uint32_t hImm:5;
+ uint32_t:7; /* 1001010 */
+ };
+} avr_opcode_JMP_1001010aaaaa110bbbbbbbbbbbbbbbbb_t;
+int avr_execute_JMP_1001010aaaaa110bbbbbbbbbbbbbbbbb(CPUAVRState *env, DisasContext *ctx, avr_opcode_JMP_1001010aaaaa110bbbbbbbbbbbbbbbbb_t const *inst);
+
+typedef union avr_opcode_CALL_1001010aaaaa111bbbbbbbbbbbbbbbbb_u {
+ uint32_t opcode;
+ struct {
+ uint32_t lImm:17;
+ uint32_t:3; /* 111 */
+ uint32_t hImm:5;
+ uint32_t:7; /* 1001010 */
+ };
+} avr_opcode_CALL_1001010aaaaa111bbbbbbbbbbbbbbbbb_t;
+int avr_execute_CALL_1001010aaaaa111bbbbbbbbbbbbbbbbb(CPUAVRState *env, DisasContext *ctx, avr_opcode_CALL_1001010aaaaa111bbbbbbbbbbbbbbbbb_t const *inst);
+
+typedef union avr_opcode_ADIW_10010110aabbcccc_u {
+ uint16_t opcode;
+ struct {
+ uint16_t lImm:4;
+ uint16_t Rd:2;
+ uint16_t hImm:2;
+ uint16_t:8; /* 10010110 */
+ };
+} avr_opcode_ADIW_10010110aabbcccc_t;
+int avr_execute_ADIW_10010110aabbcccc(CPUAVRState *env, DisasContext *ctx, avr_opcode_ADIW_10010110aabbcccc_t const *inst);
+
+typedef union avr_opcode_SBIW_10010111aabbcccc_u {
+ uint16_t opcode;
+ struct {
+ uint16_t lImm:4;
+ uint16_t Rd:2;
+ uint16_t hImm:2;
+ uint16_t:8; /* 10010111 */
+ };
+} avr_opcode_SBIW_10010111aabbcccc_t;
+int avr_execute_SBIW_10010111aabbcccc(CPUAVRState *env, DisasContext *ctx, avr_opcode_SBIW_10010111aabbcccc_t const *inst);
+
+typedef union avr_opcode_CBI_10011000aaaaabbb_u {
+ uint16_t opcode;
+ struct {
+ uint16_t Bit:3;
+ uint16_t Imm:5;
+ uint16_t:8; /* 10011000 */
+ };
+} avr_opcode_CBI_10011000aaaaabbb_t;
+int avr_execute_CBI_10011000aaaaabbb(CPUAVRState *env, DisasContext *ctx, avr_opcode_CBI_10011000aaaaabbb_t const *inst);
+
+typedef union avr_opcode_SBIC_10011001aaaaabbb_u {
+ uint16_t opcode;
+ struct {
+ uint16_t Bit:3;
+ uint16_t Imm:5;
+ uint16_t:8; /* 10011001 */
+ };
+} avr_opcode_SBIC_10011001aaaaabbb_t;
+int avr_execute_SBIC_10011001aaaaabbb(CPUAVRState *env, DisasContext *ctx, avr_opcode_SBIC_10011001aaaaabbb_t const *inst);
+
+typedef union avr_opcode_SBI_10011010aaaaabbb_u {
+ uint16_t opcode;
+ struct {
+ uint16_t Bit:3;
+ uint16_t Imm:5;
+ uint16_t:8; /* 10011010 */
+ };
+} avr_opcode_SBI_10011010aaaaabbb_t;
+int avr_execute_SBI_10011010aaaaabbb(CPUAVRState *env, DisasContext *ctx, avr_opcode_SBI_10011010aaaaabbb_t const *inst);
+
+typedef union avr_opcode_SBIS_10011011aaaaabbb_u {
+ uint16_t opcode;
+ struct {
+ uint16_t Bit:3;
+ uint16_t Imm:5;
+ uint16_t:8; /* 10011011 */
+ };
+} avr_opcode_SBIS_10011011aaaaabbb_t;
+int avr_execute_SBIS_10011011aaaaabbb(CPUAVRState *env, DisasContext *ctx, avr_opcode_SBIS_10011011aaaaabbb_t const *inst);
+
+typedef union avr_opcode_MUL_100111abbbbbcccc_u {
+ uint16_t opcode;
+ struct {
+ uint16_t lRr:4;
+ uint16_t Rd:5;
+ uint16_t hRr:1;
+ uint16_t:6; /* 100111 */
+ };
+} avr_opcode_MUL_100111abbbbbcccc_t;
+int avr_execute_MUL_100111abbbbbcccc(CPUAVRState *env, DisasContext *ctx, avr_opcode_MUL_100111abbbbbcccc_t const *inst);
+
+typedef union avr_opcode_IN_10110aabbbbbcccc_u {
+ uint16_t opcode;
+ struct {
+ uint16_t lImm:4;
+ uint16_t Rd:5;
+ uint16_t hImm:2;
+ uint16_t:5; /* 10110 */
+ };
+} avr_opcode_IN_10110aabbbbbcccc_t;
+int avr_execute_IN_10110aabbbbbcccc(CPUAVRState *env, DisasContext *ctx, avr_opcode_IN_10110aabbbbbcccc_t const *inst);
+
+typedef union avr_opcode_OUT_10111aabbbbbcccc_u {
+ uint16_t opcode;
+ struct {
+ uint16_t lImm:4;
+ uint16_t Rd:5;
+ uint16_t hImm:2;
+ uint16_t:5; /* 10111 */
+ };
+} avr_opcode_OUT_10111aabbbbbcccc_t;
+int avr_execute_OUT_10111aabbbbbcccc(CPUAVRState *env, DisasContext *ctx, avr_opcode_OUT_10111aabbbbbcccc_t const *inst);
+
+typedef union avr_opcode_RJMP_1100aaaaaaaaaaaa_u {
+ uint16_t opcode;
+ struct {
+ uint16_t Imm:12;
+ uint16_t:4; /* 1100 */
+ };
+} avr_opcode_RJMP_1100aaaaaaaaaaaa_t;
+int avr_execute_RJMP_1100aaaaaaaaaaaa(CPUAVRState *env, DisasContext *ctx, avr_opcode_RJMP_1100aaaaaaaaaaaa_t const *inst);
+
+typedef union avr_opcode_LDI_1110aaaabbbbcccc_u {
+ uint16_t opcode;
+ struct { uint16_t lImm:4;
+ uint16_t Rd:4;
+ uint16_t hImm:4;
+ uint16_t:4; /* 1110 */
+ };
+} avr_opcode_LDI_1110aaaabbbbcccc_t;
+int avr_execute_LDI_1110aaaabbbbcccc(CPUAVRState *env, DisasContext *ctx, avr_opcode_LDI_1110aaaabbbbcccc_t const *inst);
+
+typedef union avr_opcode_RCALL_1101aaaaaaaaaaaa_u {
+ uint16_t opcode;
+ struct {
+ uint16_t Imm:12;
+ uint16_t:4; /* 1101 */
+ };
+} avr_opcode_RCALL_1101aaaaaaaaaaaa_t;
+int avr_execute_RCALL_1101aaaaaaaaaaaa(CPUAVRState *env, DisasContext *ctx, avr_opcode_RCALL_1101aaaaaaaaaaaa_t const *inst);
+
+typedef union avr_opcode_BRBS_111100aaaaaaabbb_u {
+ uint16_t opcode;
+ struct {
+ uint16_t Bit:3;
+ uint16_t Imm:7;
+ uint16_t:6; /* 111100 */
+ };
+} avr_opcode_BRBS_111100aaaaaaabbb_t;
+int avr_execute_BRBS_111100aaaaaaabbb(CPUAVRState *env, DisasContext *ctx, avr_opcode_BRBS_111100aaaaaaabbb_t const *inst);
+
+typedef union avr_opcode_BRBC_111101aaaaaaabbb_u {
+ uint16_t opcode;
+ struct {
+ uint16_t Bit:3;
+ uint16_t Imm:7;
+ uint16_t:6; /* 111101 */
+ };
+} avr_opcode_BRBC_111101aaaaaaabbb_t;
+int avr_execute_BRBC_111101aaaaaaabbb(CPUAVRState *env, DisasContext *ctx, avr_opcode_BRBC_111101aaaaaaabbb_t const *inst);
+
+typedef union avr_opcode_BLD_1111100aaaaa0bbb_u {
+ uint16_t opcode;
+ struct {
+ uint16_t Bit:3;
+ uint16_t:1; /* 0 */
+ uint16_t Rd:5;
+ uint16_t:7; /* 1111100 */
+ };
+} avr_opcode_BLD_1111100aaaaa0bbb_t;
+int avr_execute_BLD_1111100aaaaa0bbb(CPUAVRState *env, DisasContext *ctx, avr_opcode_BLD_1111100aaaaa0bbb_t const *inst);
+
+typedef union avr_opcode_BST_1111101aaaaa0bbb_u {
+ uint16_t opcode;
+ struct {
+ uint16_t Bit:3;
+ uint16_t:1; /* 0 */
+ uint16_t Rd:5;
+ uint16_t:7; /* 1111101 */
+ };
+} avr_opcode_BST_1111101aaaaa0bbb_t;
+int avr_execute_BST_1111101aaaaa0bbb(CPUAVRState *env, DisasContext *ctx, avr_opcode_BST_1111101aaaaa0bbb_t const *inst);
+
+typedef union avr_opcode_SBRC_1111110aaaaa0bbb_u {
+ uint16_t opcode;
+ struct {
+ uint16_t Bit:3;
+ uint16_t:1; /* 0 */
+ uint16_t Rr:5;
+ uint16_t:7; /* 1111110 */
+ };
+} avr_opcode_SBRC_1111110aaaaa0bbb_t;
+int avr_execute_SBRC_1111110aaaaa0bbb(CPUAVRState *env, DisasContext *ctx, avr_opcode_SBRC_1111110aaaaa0bbb_t const *inst);
+
+typedef union avr_opcode_SBRS_1111111aaaaa0bbb_u {
+ uint16_t opcode;
+ struct {
+ uint16_t Bit:3;
+ uint16_t:1; /* 0 */
+ uint16_t Rr:5;
+ uint16_t:7; /* 1111111 */
+ };
+} avr_opcode_SBRS_1111111aaaaa0bbb_t;
+int avr_execute_SBRS_1111111aaaaa0bbb(CPUAVRState *env, DisasContext *ctx, avr_opcode_SBRS_1111111aaaaa0bbb_t const *inst);
+
diff --git a/target-avr/gdbstub.c b/target-avr/gdbstub.c
new file mode 100644
index 0000000..5923f49
--- /dev/null
+++ b/target-avr/gdbstub.c
@@ -0,0 +1,105 @@
+/*
+ * 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 = 0;
+
+ sreg = (env->sregC & 0x01) << 0
+ | (env->sregZ & 0x01) << 1
+ | (env->sregN & 0x01) << 2
+ | (env->sregV & 0x01) << 3
+ | (env->sregS & 0x01) << 4
+ | (env->sregH & 0x01) << 5
+ | (env->sregT & 0x01) << 6
+ | (env->sregI & 0x01) << 7;
+ 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 * 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;
+ uint16_t tmp = ldl_p(mem_buf);
+
+ /* R */
+ if (n < 32) {
+ env->r[n] = tmp;
+ }
+
+ /* SREG */
+ if (n == 32) {
+ env->sregC = (tmp >> 0) & 0x01;
+ env->sregZ = (tmp >> 1) & 0x01;
+ env->sregN = (tmp >> 2) & 0x01;
+ env->sregV = (tmp >> 3) & 0x01;
+ env->sregS = (tmp >> 4) & 0x01;
+ env->sregH = (tmp >> 5) & 0x01;
+ env->sregT = (tmp >> 6) & 0x01;
+ env->sregI = (tmp >> 7) & 0x01;
+ }
+
+ /* SP */
+ if (n == 33) {
+ env->sp = tmp;
+ return 2;
+ }
+
+ /* PC */
+ if (n == 34) {
+ env->pc = tmp / 2;
+ return 4;
+ }
+
+ return 1;
+}
diff --git a/target-avr/helper.c b/target-avr/helper.c
new file mode 100644
index 0000000..03d968f
--- /dev/null
+++ b/target-avr/helper.c
@@ -0,0 +1,280 @@
+/*
+ * 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)
+{
+ CPUClass *cc = CPU_GET_CLASS(cs);
+ AVRCPU *cpu = AVR_CPU(cs);
+ CPUAVRState *env = &cpu->env;
+
+ bool ret = false;
+
+ 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 = __builtin_ffs(env->intsrc) - 1;
+ 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;
+ int vector;
+ 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 = __builtin_ffs(env->intsrc);
+ }
+
+ if (avr_feature(env, AVR_FEATURE_3_BYTE_PC)) {
+ stb_phys(cs->as, env->sp--, (ret & 0x0000ff));
+ stb_phys(cs->as, env->sp--, (ret & 0x00ff00) >> 8);
+ stb_phys(cs->as, env->sp--, (ret & 0xff0000) >> 16);
+
+ env->pc = base + vector * size;
+ } else if (avr_feature(env, AVR_FEATURE_2_BYTE_PC)) {
+ stb_phys(cs->as, env->sp--, (ret & 0x0000ff));
+ stb_phys(cs->as, env->sp--, (ret & 0x00ff00) >> 8);
+
+ env->pc = base + vector * size;
+ } else {
+ stb_phys(cs->as, env->sp--, (ret & 0x0000ff));
+
+ env->pc = base + vector * size;
+ }
+
+ env->sregI = 0; /* clear Global Interrupt Flag */
+
+ cs->exception_index = -1;
+}
+
+int avr_cpu_memory_rw_debug(
+ CPUState *cs,
+ vaddr addr,
+ uint8_t *buf,
+ int len,
+ bool is_write)
+{
+ return cpu_memory_rw_debug(cs, addr, buf, len, is_write);
+}
+
+hwaddr avr_cpu_get_phys_page_debug(
+ CPUState *cs,
+ vaddr addr)
+{
+ return addr; /* I assume 1:1 address correspondance */
+}
+
+int avr_cpu_handle_mmu_fault(
+ CPUState *cs,
+ vaddr address,
+ int rw,
+ int mmu_idx)
+{
+ cs->exception_index = EXCP_DEBUG;
+ cpu_dump_state(cs, stderr, fprintf, 0);
+ return 1;
+}
+
+void tlb_fill(
+ CPUState *cs,
+ target_ulong vaddr,
+ int is_write,
+ 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 == CODE_INDEX) {
+ paddr = PHYS_CODE_BASE + vaddr;
+ prot = PAGE_READ | PAGE_EXEC;
+ } else {
+ paddr = PHYS_DATA_BASE + vaddr;
+ prot = PAGE_READ | PAGE_WRITE;
+ }
+
+ tlb_set_page_with_attrs(cs, vaddr, paddr, attrs, prot, mmu_idx, page_size);
+
+/* ret = avr_cpu_handle_mmu_fault(cs, addr, is_write, mmu_idx); */
+/* if (unlikely(ret)) */
+/* { */
+/* if (retaddr) */
+/* { */
+/* cpu_restore_state(cs, retaddr); */
+/* } */
+/* } */
+/* cpu_loop_exit(cs); */
+}
+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));
+
+ cs->exception_index = EXCP_DEBUG;
+ cpu_dump_state(cs, stderr, fprintf, 0);
+ cpu_loop_exit(cs);
+}
+
+void helper_debug(
+ CPUAVRState *env)
+{
+ CPUState *cs = CPU(avr_env_get_cpu(env));
+
+ cs->exception_index = EXCP_DEBUG;
+ cpu_loop_exit(cs);
+}
+
+void helper_wdr(
+ CPUAVRState *env)
+{
+ CPUState *cs = CPU(avr_env_get_cpu(env));
+
+ cs->exception_index = EXCP_DEBUG;
+ cpu_loop_exit(cs);
+}
+
+target_ulong helper_inb(
+ CPUAVRState *env,
+ uint32_t port)
+{
+ printf("in: io[%02x]\n", port);
+
+ switch (port) {
+ case 0x3b: {
+ return env->rampZ; /* RAMPZ */
+ }
+ case 0x3d: { /* SPL */
+ return env->sp & 0x00ff;
+ }
+ case 0x3e: { /* SPH */
+ return env->sp >> 8;
+ }
+ case 0x3f: { /* SREG */
+ uint8_t sreg;
+ sreg = (env->sregC & 0x01) << 0
+ | (env->sregZ & 0x01) << 1
+ | (env->sregN & 0x01) << 2
+ | (env->sregV & 0x01) << 3
+ | (env->sregS & 0x01) << 4
+ | (env->sregH & 0x01) << 5
+ | (env->sregT & 0x01) << 6
+ | (env->sregI & 0x01) << 7;
+ return sreg;
+ }
+ }
+ return 0;
+}
+
+void helper_outb(
+ CPUAVRState *env,
+ uint32_t port,
+ uint32_t data)
+{
+ printf("out:%02x -> io[%02x]\n", data, port);
+
+ 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 0x3b: {
+ env->rampZ = data & 0x01; /* RAMPZ */
+ break;
+ }
+ case 0x3d: { /* SPL */
+ if (avr_feature(env, AVR_FEATURE_2_BYTE_SP)) {
+ env->sp = (env->sp & 0xff00) | (data);
+ }
+ break;
+ }
+ case 0x3e: { /* SPH */
+ env->sp = (env->sp & 0x00ff) | (data << 8);
+ break;
+ }
+ case 0x3f: { /* SREG */
+ env->sregC = (data >> 0) & 0x01;
+ env->sregZ = (data >> 1) & 0x01;
+ env->sregN = (data >> 2) & 0x01;
+ env->sregV = (data >> 3) & 0x01;
+ env->sregS = (data >> 4) & 0x01;
+ env->sregH = (data >> 5) & 0x01;
+ env->sregT = (data >> 6) & 0x01;
+ env->sregI = (data >> 7) & 0x01;
+ break;
+ }
+ }
+}
+
diff --git a/target-avr/helper.h b/target-avr/helper.h
new file mode 100644
index 0000000..5a08cfd
--- /dev/null
+++ b/target-avr/helper.h
@@ -0,0 +1,26 @@
+/*
+ * 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(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)
diff --git a/target-avr/machine.c b/target-avr/machine.c
new file mode 100644
index 0000000..98d44e9
--- /dev/null
+++ b/target-avr/machine.c
@@ -0,0 +1,54 @@
+/*
+ * 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 "machine.h"
+
+const VMStateDescription vmstate_avr_cpu = {
+ .name = "cpu",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32_ARRAY(r, CPUAVRState, 32),
+
+ VMSTATE_UINT32(sregC, CPUAVRState),
+ VMSTATE_UINT32(sregZ, CPUAVRState),
+ VMSTATE_UINT32(sregN, CPUAVRState),
+ VMSTATE_UINT32(sregV, CPUAVRState),
+ VMSTATE_UINT32(sregS, CPUAVRState),
+ VMSTATE_UINT32(sregH, CPUAVRState),
+ VMSTATE_UINT32(sregT, CPUAVRState),
+ VMSTATE_UINT32(sregI, CPUAVRState),
+
+ VMSTATE_UINT32(rampD, CPUAVRState),
+ VMSTATE_UINT32(rampX, CPUAVRState),
+ VMSTATE_UINT32(rampY, CPUAVRState),
+ VMSTATE_UINT32(rampZ, CPUAVRState),
+
+ VMSTATE_UINT32(eind, CPUAVRState),
+ VMSTATE_UINT32(sp, CPUAVRState),
+ VMSTATE_UINT32(pc, CPUAVRState),
+
+ VMSTATE_END_OF_LIST()
+ }
+};
diff --git a/target-avr/machine.h b/target-avr/machine.h
new file mode 100644
index 0000000..4cc8d6b
--- /dev/null
+++ b/target-avr/machine.h
@@ -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>
+ */
+
+extern const VMStateDescription vmstate_avr_cpu;
diff --git a/target-avr/translate.c b/target-avr/translate.c
new file mode 100644
index 0000000..faea9bd
--- /dev/null
+++ b/target-avr/translate.c
@@ -0,0 +1,370 @@
+/*
+ * 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 "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"
+
+uint32_t get_opcode (uint8_t const *code,
+ unsigned bitBase,
+ unsigned bitSsize);
+
+typedef struct DisasContext DisasContext;
+typedef struct InstInfo InstInfo;
+
+typedef int (*execute_function_t) (CPUAVRState *env,
+ DisasContext *ctx,
+ uint8_t const *opcode);
+struct InstInfo {
+ target_long cpc;
+ target_long npc;
+ uint32_t opcode;
+ execute_function_t exec;
+ unsigned length;
+};
+
+/*This is the state at translation time. */
+struct DisasContext {
+ struct TranslationBlock *tb;
+
+ InstInfo inst[2]; /* two consequitive instructions */
+
+ /*Routine used to access memory */
+ int memidx;
+ int bstate;
+ int singlestep;
+};
+
+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 */
+};
+
+static TCGv_env cpu_env;
+
+static TCGv cpu_pc;
+
+static TCGv cpu_Cf;
+static TCGv cpu_Zf;
+static TCGv cpu_Nf;
+static TCGv cpu_Vf;
+static TCGv cpu_Sf;
+static TCGv cpu_Hf;
+static TCGv cpu_Tf;
+static TCGv cpu_If;
+
+static TCGv cpu_rampD;
+static TCGv cpu_rampX;
+static TCGv cpu_rampY;
+static TCGv cpu_rampZ;
+
+static TCGv cpu_io[64];
+static TCGv cpu_r[32];
+static TCGv cpu_eind;
+static 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), "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 < 64; i++) {
+ char name[16];
+
+ sprintf(name, "io[%d]", i);
+
+ cpu_io[i] = tcg_global_mem_new_i32(cpu_env, offsetof(CPUAVRState, io[i]), name);
+ }
+ for (i = 0; i < 32; i++) {
+ char name[16];
+
+ sprintf(name, "r[%d]", i);
+
+ cpu_r[i] = tcg_global_mem_new_i32(cpu_env, offsetof(CPUAVRState, r[i]), name);
+ }
+
+ done_init = 1;
+}
+
+static inline void gen_goto_tb(CPUAVRState *env,
+ DisasContext *ctx,
+ int n,
+ target_ulong dest)
+{
+ TranslationBlock *tb;
+
+ tb = ctx->tb;
+
+ if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)
+ && (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);
+
+ if (ctx->singlestep) {
+ gen_helper_debug(cpu_env);
+ }
+ tcg_gen_exit_tb(0);
+ }
+}
+
+#include "translate.c.inc"
+
+typedef int (*execute_function_t)(
+ CPUAVRState *env,
+ DisasContext *ctx,
+ uint8_t const *opcode);
+void avr_decode(
+ uint32_t pc,
+ uint32_t *length,
+ uint8_t const *code,
+ execute_function_t *execute);
+
+
+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->exec = NULL;
+ avr_decode(inst->cpc, &inst->length, (uint8_t const *)&inst->opcode, &inst->exec);
+
+ if (inst->length == 16) {
+ inst->npc = inst->cpc + 1;
+ inst->opcode = inst->opcode & 0x0000ffff;
+ }
+ if (inst->length == 32) {
+ inst->npc = inst->cpc + 2;
+ inst->opcode = (inst->opcode << 16)
+ | (inst->opcode >> 16);
+ }
+}
+
+uint32_t get_opcode(
+ uint8_t const *code,
+ unsigned bitBase,
+ unsigned bitSsize)
+{
+ return *(uint16_t *)code;
+}
+
+
+/*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]);
+
+ /* execute current instruction */
+ tcg_gen_insn_start(cpc);
+ num_insns++;
+
+ if (unlikely(cpu_breakpoint_test(cs, cpc * 2, BP_ANY)
+ || cpu_breakpoint_test(cs, cpc * 2 + 0x00800000, BP_ANY))) {
+ tcg_gen_movi_i32(cpu_pc, cpc);
+ gen_helper_debug(cpu_env);
+ ctx.bstate = BS_EXCP;
+ /*The address covered by the breakpoint must be included in
+ [tb->pc, tb->pc + tb->size) in order to for it to be
+ properly cleared -- thus we increment the PC here so that
+ the logic setting tb->size below does the right thing. */
+ goto done_generating;
+ }
+
+ ctx.bstate = ctx.inst[0].exec(env, &ctx, (uint8_t const *)&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 = 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;
+
+ cpu_fprintf(f, "\n");
+ cpu_fprintf(f, "PC: %06x\n", env->pc);
+ cpu_fprintf(f, "SP: %04x\n", env->sp);
+ cpu_fprintf(f, "rampX: %02x\n", env->rampX);
+ cpu_fprintf(f, "rampY: %02x\n", env->rampY);
+ cpu_fprintf(f, "rampZ: %02x\n", env->rampZ);
+ cpu_fprintf(f, "rampD: %02x\n", env->rampD);
+ 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, " [ I T H S V N Z C ]\n");
+ cpu_fprintf(f, "SREG: [ %d %d %d %d %d %d %d %d ]\n",
+ env->sregI,
+ env->sregT,
+ env->sregH,
+ env->sregS,
+ env->sregV,
+ env->sregN,
+ env->sregZ,
+ env->sregC);
+
+ cpu_fprintf(f, "\n");
+ for (int 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");
+ for (int i = 0; i < ARRAY_SIZE(env->io); i++) {
+ cpu_fprintf(f, "IO[%02d]: %02x ", i, env->io[i]);
+
+ if ((i % 8) == 7) {
+ cpu_fprintf(f, "\n");
+ }
+ }
+}
diff --git a/target-avr/translate.c.inc b/target-avr/translate.c.inc
new file mode 100644
index 0000000..cfc3660
--- /dev/null
+++ b/target-avr/translate.c.inc
@@ -0,0 +1,2701 @@
+/*
+ * 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 <stdio.h>
+#include <stdint.h>
+#include "decode.h"
+
+/* NOTE: all registers are assumed to hold 8 bit values. */
+/* so all operations done on registers should preseve this property */
+
+/* NOTE: the flags C,H,V,N,V have either 0 or 1 values */
+/* NOTE: the flag Z has inverse logic, when the value of Zf is 0 the flag is assumed to be set, non zero - not set */
+
+void gen_add_CHf( TCGv R, TCGv Rd, TCGv Rr);
+void gen_add_Vf( TCGv R, TCGv Rd, TCGv Rr);
+void gen_sub_CHf( TCGv R, TCGv Rd, TCGv Rr);
+void gen_sub_Vf( TCGv R, TCGv Rd, TCGv Rr);
+void gen_ZNSf( TCGv R);
+void gen_push_ret( CPUAVRState *env, int ret);
+void gen_pop_ret( CPUAVRState *env, TCGv ret);
+void gen_jmp_ez( void);
+void gen_jmp_z( void);
+void gen_split_addr( TCGv addr, TCGv H, TCGv M, TCGv l);
+int sex(int Imm, unsigned bits);
+
+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_not_tl( t2, R); /* t2 = Rd & ~R */
+ tcg_gen_and_tl( t2, Rd, t2);
+ tcg_gen_not_tl( t3, R); /* t3 = Rr *~R */
+ tcg_gen_and_tl( t3, Rr, t3);
+ 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);
+}
+
+void gen_add_Vf(TCGv R, TCGv Rd, TCGv Rr)
+{
+ TCGv t1 = tcg_temp_new_i32();
+ TCGv t2 = tcg_temp_new_i32();
+
+ tcg_gen_not_tl( t1, Rd); /* t1 = ~Rd & ~Rr & R */
+ tcg_gen_not_tl( t2, Rr);
+ tcg_gen_and_tl( t1, t1, t2);
+ tcg_gen_and_tl( t1, t1, R);
+
+ tcg_gen_not_tl( t2, R); /* t2 = Rd & Rr & ~R */
+ tcg_gen_and_tl( t2, t2, Rd);
+ tcg_gen_and_tl( t2, t2, Rr);
+
+ tcg_gen_or_tl( t1, t1, t2); /* t1 = Rd & Rr & ~R | ~Rd & ~Rr & R */
+
+ tcg_gen_shri_tl(cpu_Vf, t1, 7); /* Vf = t1(7) */
+
+ tcg_temp_free_i32(t2);
+ tcg_temp_free_i32(t1);
+}
+
+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);
+}
+
+void gen_sub_Vf(TCGv R, TCGv Rd, TCGv Rr)
+{
+ TCGv t1 = tcg_temp_new_i32();
+ TCGv t2 = tcg_temp_new_i32();
+
+ /* Vf */
+ tcg_gen_and_tl( t1, Rr, R); /* t1 = Rd & ~Rr & ~R */
+ tcg_gen_not_tl( t1, t1);
+ tcg_gen_and_tl( t1, t1, Rd);
+ tcg_gen_not_tl( t2, Rd); /* t2 = ~Rd & Rr & R */
+ tcg_gen_and_tl( t2, t2, Rr);
+ tcg_gen_and_tl( t2, t2, R);
+ tcg_gen_or_tl( t1, t1, t2); /* t1 = Rd & ~Rr & ~R | ~Rd & Rr & R */
+ tcg_gen_shri_tl(cpu_Vf, t1, 7); /* Vf = t1(7) */
+
+ tcg_temp_free_i32(t2);
+ tcg_temp_free_i32(t1);
+}
+
+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_and_tl( cpu_Sf, cpu_Nf, cpu_Vf);/* Sf = Nf & Vf */
+}
+
+void gen_push_ret( CPUAVRState *env, int ret)
+{
+ tcg_gen_qemu_st8( tcg_const_local_i32((ret & 0x0000ff)), cpu_sp, DATA_INDEX);
+ tcg_gen_subi_tl( cpu_sp, cpu_sp, 1);
+
+ if ( avr_feature(env, AVR_FEATURE_2_BYTE_PC)
+ || avr_feature(env, AVR_FEATURE_3_BYTE_PC)) {
+ tcg_gen_qemu_st8( tcg_const_local_i32((ret & 0x00ff00) >> 8), cpu_sp, DATA_INDEX);
+ tcg_gen_subi_tl( cpu_sp, cpu_sp, 1);
+ }
+
+ if (avr_feature(env, AVR_FEATURE_3_BYTE_PC)) {
+ tcg_gen_qemu_st8( tcg_const_local_i32((ret & 0xff0000) >> 16),cpu_sp, DATA_INDEX);
+ tcg_gen_subi_tl( cpu_sp, cpu_sp, 1);
+ }
+}
+
+void gen_pop_ret( CPUAVRState *env, TCGv ret)
+{
+ TCGv t0 = tcg_const_i32(0);
+ TCGv t1 = tcg_const_i32(0);
+ TCGv t2 = tcg_const_i32(0);
+
+ if (avr_feature(env, AVR_FEATURE_3_BYTE_PC)) {
+ tcg_gen_addi_tl( cpu_sp, cpu_sp, 1);
+ tcg_gen_qemu_ld8u( t2, cpu_sp, DATA_INDEX);
+ tcg_gen_shli_tl( t2, t2, 16);
+ }
+
+ if ( avr_feature(env, AVR_FEATURE_2_BYTE_PC)
+ || avr_feature(env, AVR_FEATURE_3_BYTE_PC)) {
+ tcg_gen_addi_tl( cpu_sp, cpu_sp, 1);
+ tcg_gen_qemu_ld8u( t1, cpu_sp, DATA_INDEX);
+ tcg_gen_shli_tl( t1, t1, 8);
+ }
+
+ tcg_gen_addi_tl( cpu_sp, cpu_sp, 1);
+ tcg_gen_qemu_ld8u( t0, cpu_sp, DATA_INDEX);
+
+ tcg_gen_or_tl( ret, t0, t1);
+ tcg_gen_or_tl( ret, ret, t2);
+
+ tcg_temp_free_i32(t0);
+ tcg_temp_free_i32(t1);
+ tcg_temp_free_i32(t2);
+}
+
+void gen_jmp_ez()
+{
+ tcg_gen_mov_tl( cpu_pc, cpu_eind);
+ tcg_gen_shli_tl( cpu_pc, cpu_pc, 8);
+ tcg_gen_or_tl( cpu_pc, cpu_pc, cpu_r[31]);
+ tcg_gen_shli_tl( cpu_pc, cpu_pc, 8);
+ tcg_gen_or_tl( cpu_pc, cpu_pc, cpu_r[30]);
+ tcg_gen_andi_tl( cpu_pc, cpu_pc, 0xffffff);
+ tcg_gen_exit_tb(0);
+}
+
+void gen_jmp_z()
+{
+ tcg_gen_mov_tl( cpu_pc, cpu_r[31]);
+ tcg_gen_shli_tl( cpu_pc, cpu_pc, 8);
+ tcg_gen_or_tl( cpu_pc, cpu_pc, cpu_r[30]);
+ tcg_gen_andi_tl( cpu_pc, cpu_pc, 0xffff);
+ tcg_gen_exit_tb(0);
+}
+
+void gen_split_addr( TCGv addr, TCGv H, TCGv M, TCGv L)
+{
+ tcg_gen_andi_tl(L, addr, 0xff);
+
+ tcg_gen_shri_tl(addr, addr, 8);
+ tcg_gen_andi_tl(M, addr, 0xff);
+
+ tcg_gen_shri_tl(addr, addr, 8);
+ tcg_gen_andi_tl(H, addr, 0xff);
+}
+
+int sex(int Imm, unsigned bits)
+{
+ Imm <<= 32 - bits;
+ Imm >>= 32 - bits;
+
+ return Imm;
+}
+
+
+/* Adds two registers and the contents of the C Flag and places the result in the destination register Rd. */
+int avr_execute_ADC_000111abbbbbcccc(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_ADC_000111abbbbbcccc_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rd];
+ TCGv Rr = cpu_r[(inst->hRr << 4) | (inst->lRr)];
+ 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_execute_ADD_000011abbbbbcccc(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_ADD_000011abbbbbcccc_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rd];
+ TCGv Rr = cpu_r[(inst->hRr << 4) | (inst->lRr)];
+ 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_execute_ADIW_10010110aabbcccc(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_ADIW_10010110aabbcccc_t const *inst)
+{
+ if (avr_feature(env, AVR_FEATURE_ADIW_SBIW) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv RdL = cpu_r[24 + 2 *inst->Rd];
+ TCGv RdH = cpu_r[25 + 2 *inst->Rd];
+ int Imm = (inst->hImm << 4) | (inst->lImm);
+ TCGv R = tcg_temp_new_i32();
+ TCGv Rd = tcg_temp_new_i32();
+ TCGv t0 = tcg_temp_new_i32();
+
+ /* op */
+ tcg_gen_shli_tl(Rd, RdH, 8); /* R = ((H << 8) | L) + Imm */
+ tcg_gen_or_tl( Rd, RdL, Rd);
+ tcg_gen_addi_tl(R, Rd, Imm);
+ tcg_gen_andi_tl(R, R, 0xffff);/* make it 16 bits */
+
+ /* Cf */
+ tcg_gen_not_tl( t0, R); /* t0 = Rd & ~R */
+ tcg_gen_and_tl( t0, Rd, t0);
+ tcg_gen_shri_tl(cpu_Cf, t0, 15); /* Cf = t0(15) */
+
+ /* Vf */
+ tcg_gen_not_tl( t0, Rd); /* t0 = ~Rd & R */
+ tcg_gen_and_tl( t0, R, t0);
+
+ tcg_gen_shri_tl(cpu_Vf, t0, 15); /* Vf = t0(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_and_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(t0);
+ 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_execute_AND_001000abbbbbcccc(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_AND_001000abbbbbcccc_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rd];
+ TCGv Rr = cpu_r[(inst->hRr << 4) | (inst->lRr)];
+ 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_execute_ANDI_0111aaaabbbbcccc(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_ANDI_0111aaaabbbbcccc_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rd];
+ int Imm = (inst->hImm << 4) | (inst->lImm);
+
+ /* 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_execute_ASR_1001010aaaaa0101(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_ASR_1001010aaaaa0101_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rd];
+ 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_execute_BCLR_100101001aaa1000(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_BCLR_100101001aaa1000_t const *inst)
+{
+ switch(inst->Bit) {
+ 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_execute_BLD_1111100aaaaa0bbb(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_BLD_1111100aaaaa0bbb_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rd];
+ TCGv t1 = tcg_temp_new_i32();
+
+ tcg_gen_shli_tl(t1, cpu_Tf, inst->Bit);
+ tcg_gen_or_tl( Rd, Rd, t1);
+ tcg_gen_and_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_execute_BRBC_111101aaaaaaabbb(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_BRBC_111101aaaaaaabbb_t const *inst)
+{
+ TCGLabel *taken = gen_new_label();
+ int Imm = sex(inst->Imm, 7);
+
+ switch(inst->Bit) {
+ 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_execute_BRBS_111100aaaaaaabbb(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_BRBS_111100aaaaaaabbb_t const *inst)
+{
+ TCGLabel *taken = gen_new_label();
+ int Imm = sex(inst->Imm, 7);
+
+ switch(inst->Bit) {
+ 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_execute_BSET_100101000aaa1000(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_BSET_100101000aaa1000_t const *inst)
+{
+ switch(inst->Bit) {
+ 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_execute_BREAK_1001010110011000(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_BREAK_1001010110011000_t const *inst)
+{
+ 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_execute_BST_1111101aaaaa0bbb(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_BST_1111101aaaaa0bbb_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rd];
+
+ tcg_gen_andi_tl(cpu_Tf, Rd, 1 << inst->Bit);
+ tcg_gen_shri_tl(cpu_Tf, cpu_Tf, inst->Bit);
+
+ 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_execute_CALL_1001010aaaaa111bbbbbbbbbbbbbbbbb(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_CALL_1001010aaaaa111bbbbbbbbbbbbbbbbb_t const *inst)
+{
+ if (avr_feature(env, AVR_FEATURE_JMP_CALL) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ int Imm = (inst->hImm << 17) | inst->lImm;
+ 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_execute_CBI_10011000aaaaabbb(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_CBI_10011000aaaaabbb_t const *inst)
+{
+ TCGv data= cpu_io[inst->Imm];
+ TCGv port= tcg_const_i32(inst->Imm);
+
+ tcg_gen_andi_tl(data, data, ~(1 << inst->Bit));
+ gen_helper_outb(cpu_env,port, data);
+
+ 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_execute_COM_1001010aaaaa0000(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_COM_1001010aaaaa0000_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rd];
+ TCGv R = tcg_temp_new_i32();
+
+ tcg_gen_movi_tl(R, 0xff);
+ tcg_gen_sub_tl( Rd, R, Rd);
+
+ 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_execute_CP_000101abbbbbcccc(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_CP_000101abbbbbcccc_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rd];
+ TCGv Rr = cpu_r[(inst->hRr << 4) | (inst->lRr)];
+ 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_execute_CPC_000001abbbbbcccc(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_CPC_000001abbbbbcccc_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rd];
+ TCGv Rr = cpu_r[(inst->hRr << 4) | (inst->lRr)];
+ 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);
+
+ 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_execute_CPI_0011aaaabbbbcccc(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_CPI_0011aaaabbbbcccc_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rd];
+ int Imm = (inst->hImm << 4) | inst->lImm;
+ 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);
+
+ return BS_NONE;
+}
+
+
+/* This instruction performs a compare between two registers Rd and Rr, and skips the next instruction if Rd = Rr. */
+int avr_execute_CPSE_000100abbbbbcccc(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_CPSE_000100abbbbbcccc_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rd];
+ TCGv Rr = cpu_r[(inst->hRr << 4) | (inst->lRr)];
+ TCGLabel *skip= gen_new_label();
+
+ tcg_gen_movi_tl( cpu_pc, ctx->inst[1].npc); /* PC if next inst is skipped */
+ tcg_gen_brcond_i32( TCG_COND_EQ, Rd, Rr, skip);
+ tcg_gen_movi_tl( cpu_pc, ctx->inst[0].npc); /* PC if next inst is not skipped */
+ 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_execute_DEC_1001010aaaaa1010(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_DEC_1001010aaaaa1010_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rd];
+
+ tcg_gen_subi_tl(Rd, Rd, 1); /* Rd = Rd - 1 */
+ tcg_gen_andi_tl(Rd, Rd, 0xff); /* make it 8 bits */
+
+ tcg_gen_setcondi_tl( TCG_COND_EQ, cpu_Vf, Rd, 0x7f); /* cpu_Vf = Rd == 0x7f */
+ gen_ZNSf(Rd);
+
+ return BS_NONE;
+}
+
+int avr_execute_DES_10010100aaaa1011(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_DES_10010100aaaa1011_t const *inst)
+{
+ /* 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_execute_EICALL_1001010100011001(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_EICALL_1001010100011001_t const *inst)
+{
+ 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_execute_EIJMP_1001010000011001(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_EIJMP_1001010000011001_t const *inst)
+{
+ 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_execute_ELPM1_1001010111011000(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_ELPM1_1001010111011000_t const *inst)
+{
+ if (avr_feature(env, AVR_FEATURE_ELPM) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv Rd = cpu_r[0];
+ TCGv addr= tcg_temp_new_i32();
+ TCGv H = cpu_rampZ;
+ TCGv M = cpu_r[31];
+ TCGv L = cpu_r[30];
+
+ tcg_gen_mov_tl( addr, H); /* addr = rampZ:r31:r30 */
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, M);
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, L);
+
+ tcg_gen_qemu_ld8u(Rd, addr, CODE_INDEX); /* Rd = mem[addr] */
+
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+int avr_execute_ELPM2_1001000aaaaa0110(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_ELPM2_1001000aaaaa0110_t const *inst)
+{
+ if (avr_feature(env, AVR_FEATURE_ELPM) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv Rd = cpu_r[inst->Rd];
+ TCGv addr= tcg_temp_new_i32();
+ TCGv H = cpu_rampZ;
+ TCGv M = cpu_r[31];
+ TCGv L = cpu_r[30];
+
+ tcg_gen_mov_tl( addr, H); /* addr = rampZ:r31:r30 */
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, M);
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, L);
+
+ tcg_gen_qemu_ld8u(Rd, addr, CODE_INDEX); /* Rd = mem[addr] */
+
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+int avr_execute_ELPMX_1001000aaaaa0111(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_ELPMX_1001000aaaaa0111_t const *inst)
+{
+ if (avr_feature(env, AVR_FEATURE_ELPMX) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv Rd = cpu_r[inst->Rd];
+ TCGv addr= tcg_temp_new_i32();
+ TCGv H = cpu_rampZ;
+ TCGv M = cpu_r[31];
+ TCGv L = cpu_r[30];
+
+
+ tcg_gen_mov_tl( addr, H); /* addr = rampZ:r31:r30 */
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, M);
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, L);
+
+ tcg_gen_qemu_ld8u(Rd, addr, CODE_INDEX); /* 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(M, addr, 0xff);
+
+ tcg_gen_shri_tl(addr, addr, 8);
+ tcg_gen_andi_tl(H, addr, 0xff);
+
+ 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_execute_EOR_001001abbbbbcccc(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_EOR_001001abbbbbcccc_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rd];
+ TCGv Rr = cpu_r[(inst->hRr << 4) | (inst->lRr)];
+ TCGv R = tcg_temp_new_i32();
+
+ tcg_gen_xor_tl( R, Rd, Rr);
+
+ tcg_gen_movi_tl(cpu_Vf, 0);
+ gen_ZNSf(R);
+
+ tcg_temp_free_i32(R);
+
+ return BS_NONE;
+}
+
+
+/* This instruction performs 8-bit x 8-bit -> 16-bit unsigned multiplication and shifts the result one bit left. */
+int avr_execute_FMUL_000000110aaa1bbb(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_FMUL_000000110aaa1bbb_t const *inst)
+{
+ 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 + inst->Rd];
+ TCGv Rr = cpu_r[16 + inst->Rr];
+ 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_execute_FMULS_000000111aaa0bbb(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_FMULS_000000111aaa0bbb_t const *inst)
+{
+ 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 + inst->Rd];
+ TCGv Rr = cpu_r[16 + inst->Rr];
+ TCGv R = tcg_temp_new_i32();
+
+ tcg_gen_ext8s_tl( Rd, Rd); /* make Rd full 32 bit signed */
+ tcg_gen_ext8s_tl( Rr, Rr); /* make Rr full 32 bit signed */
+ 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_execute_FMULSU_000000111aaa1bbb(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_FMULSU_000000111aaa1bbb_t const *inst)
+{
+ 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 + inst->Rd];
+ TCGv Rr = cpu_r[16 + inst->Rr];
+ TCGv R = tcg_temp_new_i32();
+
+ tcg_gen_ext8s_tl( Rd, Rd); /* make Rd full 32 bit signed */
+ 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);
+
+ 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_execute_ICALL_1001010100001001(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_ICALL_1001010100001001_t const *inst)
+{
+ 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_execute_IJMP_1001010000001001(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_IJMP_1001010000001001_t const *inst)
+{
+ 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_execute_IN_10110aabbbbbcccc(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_IN_10110aabbbbbcccc_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rd];
+ int Imm = (inst->hImm << 4) | inst->lImm;
+ TCGv port= tcg_const_i32(Imm);
+ TCGv data= cpu_io[Imm];
+
+ gen_helper_inb( data, cpu_env,port);
+ tcg_gen_mov_tl( Rd, data);
+
+ 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_execute_INC_1001010aaaaa0011(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_INC_1001010aaaaa0011_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rd];
+
+ tcg_gen_addi_tl(Rd, Rd, 1);
+ tcg_gen_andi_tl(Rd, Rd, 0xff);
+
+ tcg_gen_setcondi_tl( TCG_COND_EQ, cpu_Vf, Rd, 0x80); /* 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_execute_JMP_1001010aaaaa110bbbbbbbbbbbbbbbbb(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_JMP_1001010aaaaa110bbbbbbbbbbbbbbbbb_t const *inst)
+{
+ if (avr_feature(env, AVR_FEATURE_JMP_CALL) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ gen_goto_tb(env, ctx, 0, (inst->hImm << 17) | inst->lImm);
+ 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. */
+int avr_execute_LAC_1001001aaaaa0110(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_LAC_1001001aaaaa0110_t const *inst)
+{
+ if (avr_feature(env, AVR_FEATURE_RMW) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv Rr = cpu_r[inst->Rr];
+ TCGv addr= tcg_temp_new_i32();
+ TCGv t0 = tcg_temp_new_i32();
+ TCGv t1 = tcg_temp_new_i32();
+ TCGv H = cpu_rampZ;
+ TCGv M = cpu_r[31];
+ TCGv L = cpu_r[30];
+
+ tcg_gen_mov_tl( addr, H); /* addr = rampZ:r31:r30 */
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, M);
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, L);
+
+ tcg_gen_qemu_ld8u(
+ t0, addr, DATA_INDEX); /* t0 = mem[addr] */
+ tcg_gen_movi_tl(t1, 0xff); /* t1 = t0 & (0xff - Rr) */
+ tcg_gen_sub_tl( t1, t1, Rr);
+ tcg_gen_and_tl( t1, t0, t1);
+
+ tcg_gen_mov_tl( Rr, t0); /* Rr = t0 */
+ tcg_gen_qemu_st8( t1, addr, DATA_INDEX); /* 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_execute_LAS_1001001aaaaa0101(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_LAS_1001001aaaaa0101_t const *inst)
+{
+ if (avr_feature(env, AVR_FEATURE_RMW) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv Rr = cpu_r[inst->Rr];
+ TCGv addr= tcg_temp_new_i32();
+ TCGv t0 = tcg_temp_new_i32();
+ TCGv t1 = tcg_temp_new_i32();
+ TCGv H = cpu_rampZ;
+ TCGv M = cpu_r[31];
+ TCGv L = cpu_r[30];
+
+ tcg_gen_mov_tl( addr, H); /* addr = rampZ:r31:r30 */
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, M);
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, L);
+
+ tcg_gen_qemu_ld8u(
+ t0, addr, DATA_INDEX); /* t0 = mem[addr] */
+ tcg_gen_or_tl( t1, t0, Rr);
+
+ tcg_gen_mov_tl( Rr, t0); /* Rr = t0 */
+ tcg_gen_qemu_st8( t1, addr, DATA_INDEX); /* 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_execute_LAT_1001001aaaaa0111(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_LAT_1001001aaaaa0111_t const *inst)
+{
+ if (avr_feature(env, AVR_FEATURE_RMW) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv Rr = cpu_r[inst->Rr];
+ TCGv addr= tcg_temp_new_i32();
+ TCGv t0 = tcg_temp_new_i32();
+ TCGv t1 = tcg_temp_new_i32();
+ TCGv H = cpu_rampZ;
+ TCGv M = cpu_r[31];
+ TCGv L = cpu_r[30];
+
+ tcg_gen_mov_tl( addr, H); /* addr = rampZ:r31:r30 */
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, M);
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, L);
+
+ tcg_gen_qemu_ld8u(
+ t0, addr, DATA_INDEX); /* t0 = mem[addr] */
+ tcg_gen_xor_tl( t1, t0, Rr);
+
+ tcg_gen_mov_tl( Rr, t0); /* Rr = t0 */
+ tcg_gen_qemu_st8( t1, addr, DATA_INDEX); /* 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_execute_LDX1_1001000aaaaa1100(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_LDX1_1001000aaaaa1100_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rd];
+ TCGv addr= tcg_temp_new_i32();
+ TCGv H = cpu_rampX;
+ TCGv M = cpu_r[27];
+ TCGv L = cpu_r[26];
+
+ tcg_gen_mov_tl( addr, H); /* addr = H:M:L */
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, M);
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, L);
+
+ tcg_gen_qemu_ld8u(
+ Rd, addr, DATA_INDEX);
+
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+int avr_execute_LDX2_1001000aaaaa1101(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_LDX2_1001000aaaaa1101_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rd];
+ TCGv addr= tcg_temp_new_i32();
+ TCGv H = cpu_rampX;
+ TCGv M = cpu_r[27];
+ TCGv L = cpu_r[26];
+
+ tcg_gen_mov_tl( addr, H); /* addr = H:M:L */
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, M);
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, L);
+
+ tcg_gen_qemu_ld8u(
+ Rd, addr, DATA_INDEX);
+ tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
+
+ gen_split_addr( addr, H, M, L);
+
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+int avr_execute_LDX3_1001000aaaaa1110(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_LDX3_1001000aaaaa1110_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rd];
+ TCGv addr= tcg_temp_new_i32();
+ TCGv H = cpu_rampX;
+ TCGv M = cpu_r[27];
+ TCGv L = cpu_r[26];
+
+ tcg_gen_mov_tl( addr, H); /* addr = H:M:L */
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, M);
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, L);
+
+ tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */
+ tcg_gen_qemu_ld8u(
+ Rd, addr, DATA_INDEX);
+
+ gen_split_addr( addr, H, M, L);
+
+ 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_execute_LDY2_1001000aaaaa1001(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_LDY2_1001000aaaaa1001_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rd];
+ TCGv addr= tcg_temp_new_i32();
+ TCGv H = cpu_rampY;
+ TCGv M = cpu_r[29];
+ TCGv L = cpu_r[28];
+
+ tcg_gen_mov_tl( addr, H); /* addr = H:M:L */
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, M);
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, L);
+
+ tcg_gen_qemu_ld8u(
+ Rd, addr, DATA_INDEX);
+ tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
+
+ gen_split_addr( addr, H, M, L);
+
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+int avr_execute_LDY3_1001000aaaaa1010(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_LDY3_1001000aaaaa1010_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rd];
+ TCGv addr= tcg_temp_new_i32();
+ TCGv H = cpu_rampY;
+ TCGv M = cpu_r[29];
+ TCGv L = cpu_r[28];
+
+ tcg_gen_mov_tl( addr, H); /* addr = H:M:L */
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, M);
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, L);
+
+ tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */
+ tcg_gen_qemu_ld8u(
+ Rd, addr, DATA_INDEX);
+
+ gen_split_addr( addr, H, M, L);
+
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+int avr_execute_LDDY_10a0bb0ccccc1ddd(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_LDDY_10a0bb0ccccc1ddd_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rd];
+ TCGv addr= tcg_temp_new_i32();
+ TCGv H = cpu_rampY;
+ TCGv M = cpu_r[29];
+ TCGv L = cpu_r[28];
+
+ tcg_gen_mov_tl( addr, H); /* addr = H:M:L */
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, M);
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, L);
+
+ tcg_gen_addi_tl(addr, addr, (inst->hImm << 5) | (inst->mImm << 2) | inst->lImm);
+ /* addr = addr + q */
+ tcg_gen_qemu_ld8u(
+ Rd, addr, DATA_INDEX);
+
+ 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_execute_LDZ2_1001000aaaaa0001(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_LDZ2_1001000aaaaa0001_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rd];
+ TCGv addr= tcg_temp_new_i32();
+ TCGv H = cpu_rampZ;
+ TCGv M = cpu_r[31];
+ TCGv L = cpu_r[30];
+
+ tcg_gen_mov_tl( addr, H); /* addr = H:M:L */
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, M);
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, L);
+
+ tcg_gen_qemu_ld8u(
+ Rd, addr, DATA_INDEX);
+ tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
+
+ gen_split_addr( addr, H, M, L);
+
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+int avr_execute_LDZ3_1001000aaaaa0010(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_LDZ3_1001000aaaaa0010_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rd];
+ TCGv addr= tcg_temp_new_i32();
+ TCGv H = cpu_rampZ;
+ TCGv M = cpu_r[31];
+ TCGv L = cpu_r[30];
+
+ tcg_gen_mov_tl( addr, H); /* addr = H:M:L */
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, M);
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, L);
+
+ tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */
+ tcg_gen_qemu_ld8u(
+ Rd, addr, DATA_INDEX);
+
+ gen_split_addr( addr, H, M, L);
+
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+int avr_execute_LDDZ_10a0bb0ccccc0ddd(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_LDDZ_10a0bb0ccccc0ddd_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rd];
+ TCGv addr= tcg_temp_new_i32();
+ TCGv H = cpu_rampZ;
+ TCGv M = cpu_r[31];
+ TCGv L = cpu_r[30];
+
+ tcg_gen_mov_tl( addr, H); /* addr = H:M:L */
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, M);
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, L);
+
+ tcg_gen_addi_tl(addr, addr, (inst->hImm << 5) | (inst->mImm << 2) | inst->lImm);
+ /* addr = addr + q */
+ tcg_gen_qemu_ld8u(
+ Rd, addr, DATA_INDEX);
+
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+
+/* Loads an 8 bit constant directly to register 16 to 31. */
+int avr_execute_LDI_1110aaaabbbbcccc(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_LDI_1110aaaabbbbcccc_t const *inst)
+{
+ TCGv Rd = cpu_r[16 + inst->Rd];
+ int imm = (inst->hImm << 4) | inst->lImm;
+
+ 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_execute_LDS_1001000aaaaa0000bbbbbbbbbbbbbbbb(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_LDS_1001000aaaaa0000bbbbbbbbbbbbbbbb_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rd];
+ 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, inst->Imm);
+
+ tcg_gen_qemu_ld8u(
+ Rd, addr, DATA_INDEX);
+
+ 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_execute_LPM1_1001010111001000(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_LPM1_1001010111001000_t const *inst)
+{
+ 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, CODE_INDEX); /* Rd = mem[addr] */
+
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+int avr_execute_LPM2_1001000aaaaa0100(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_LPM2_1001000aaaaa0100_t const *inst)
+{
+ if (avr_feature(env, AVR_FEATURE_LPM) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv Rd = cpu_r[inst->Rd];
+ TCGv addr= tcg_temp_new_i32();
+ TCGv H = cpu_r[31];
+ TCGv L = cpu_r[30];
+
+ tcg_gen_shli_tl(addr, H, 8); /* addr = H:L */
+ tcg_gen_or_tl( addr, addr, L);
+
+ tcg_gen_qemu_ld8u(Rd, addr, CODE_INDEX); /* Rd = mem[addr] */
+
+ tcg_temp_free_i32(addr);
+
+
+ return BS_NONE;
+}
+
+int avr_execute_LPMX_1001000aaaaa0101(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_LPMX_1001000aaaaa0101_t const *inst)
+{
+ if (avr_feature(env, AVR_FEATURE_LPMX) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv Rd = cpu_r[inst->Rd];
+ TCGv addr= tcg_temp_new_i32();
+ TCGv H = cpu_r[31];
+ TCGv L = cpu_r[30];
+
+ tcg_gen_shli_tl(addr, H, 8); /* addr = H:L */
+ tcg_gen_or_tl( addr, addr, L);
+
+ tcg_gen_qemu_ld8u(Rd, addr, CODE_INDEX); /* 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_execute_LSR_1001010aaaaa0110(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_LSR_1001010aaaaa0110_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rd];
+
+ 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_execute_MOV_001011abbbbbcccc(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_MOV_001011abbbbbcccc_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rd];
+ TCGv Rr = cpu_r[(inst->hRr << 4) | (inst->lRr)];
+
+ 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_execute_MOVW_00000001aaaabbbb(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_MOVW_00000001aaaabbbb_t const *inst)
+{
+ if (avr_feature(env, AVR_FEATURE_MOVW) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv RdL = cpu_r[inst->Rd *2 + 0];
+ TCGv RdH = cpu_r[inst->Rd *2 + 1];
+ TCGv RrL = cpu_r[inst->Rr *2 + 0];
+ TCGv RrH = cpu_r[inst->Rr *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_execute_MUL_100111abbbbbcccc(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_MUL_100111abbbbbcccc_t const *inst)
+{
+ 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[inst->Rd];
+ TCGv Rr = cpu_r[(inst->hRr << 4) | inst->lRr];
+ 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_execute_MULS_00000010aaaabbbb(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_MULS_00000010aaaabbbb_t const *inst)
+{
+ 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 + inst->Rd];
+ TCGv Rr = cpu_r[16 + inst->Rr];
+ TCGv R = tcg_temp_new_i32();
+
+ tcg_gen_ext8s_tl( Rd, Rd); /* make Rd full 32 bit signed */
+ tcg_gen_ext8s_tl( Rr, Rr); /* make Rr full 32 bit signed */
+ 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_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(R);
+
+ return BS_NONE;
+}
+
+/* This instruction performs 8-bit x 8-bit -> 16-bit multiplication of a signed and an unsigned number. */
+int avr_execute_MULSU_000000110aaa0bbb(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_MULSU_000000110aaa0bbb_t const *inst)
+{
+ 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 + inst->Rd];
+ TCGv Rr = cpu_r[16 + inst->Rr];
+ TCGv R = tcg_temp_new_i32();
+
+ tcg_gen_ext8s_tl( Rd, Rd); /* make Rd full 32 bit signed */
+ 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_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(R);
+
+ return BS_NONE;
+}
+
+/* Replaces the contents of register Rd with its two’s complement; the value $80 is left unchanged. */
+int avr_execute_NEG_1001010aaaaa0001(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_NEG_1001010aaaaa0001_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rd];
+ TCGv R = tcg_temp_new_i32();
+
+ tcg_gen_neg_tl( R, Rd);
+
+ tcg_gen_setcondi_tl(TCG_COND_NE,cpu_Cf, R, 0x00); /* Cf = R != 0x00 */
+ tcg_gen_setcondi_tl(TCG_COND_EQ,cpu_Vf, R, 0x80); /* Vf = R == 0x80 */
+ tcg_gen_not_tl( cpu_Hf, Rd); /* Hf = (~Rd | R)(3) */
+ tcg_gen_or_tl( cpu_Hf, cpu_Hf, R);
+ tcg_gen_shri_tl(cpu_Hf, cpu_Hf, 3);
+ tcg_gen_andi_tl(cpu_Hf, cpu_Hf, 1);
+ gen_ZNSf( R);
+
+ tcg_temp_free_i32(R);
+
+ return BS_NONE;
+}
+
+
+/* This instruction performs a single cycle No Operation. */
+int avr_execute_NOP_0000000000000000(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_NOP_0000000000000000_t const *inst)
+{
+
+ /* 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_execute_OR_001010abbbbbcccc(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_OR_001010abbbbbcccc_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rd];
+ TCGv Rr = cpu_r[(inst->hRr << 4) | (inst->lRr)];
+ 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_execute_ORI_0110aaaabbbbcccc(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_ORI_0110aaaabbbbcccc_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rd];
+ int Imm = (inst->hImm << 4) | (inst->lImm);
+
+ 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_execute_OUT_10111aabbbbbcccc(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_OUT_10111aabbbbbcccc_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rd];
+ int Imm = (inst->hImm << 4) | inst->lImm;
+ TCGv port= tcg_const_i32(Imm);
+ TCGv data= cpu_io[Imm];
+
+ tcg_gen_mov_tl( data, Rd);
+ gen_helper_outb(cpu_env,port, data);
+
+ 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_execute_POP_1001000aaaaa1111(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_POP_1001000aaaaa1111_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rd];
+
+ tcg_gen_addi_tl(cpu_sp, cpu_sp, 1);
+ tcg_gen_qemu_ld8u(
+ Rd, cpu_sp, DATA_INDEX);
+
+ 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_execute_PUSH_1001001aaaaa1111(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_PUSH_1001001aaaaa1111_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rd];
+
+ tcg_gen_qemu_st8(
+ Rd, cpu_sp, DATA_INDEX);
+ 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_execute_RCALL_1101aaaaaaaaaaaa(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_RCALL_1101aaaaaaaaaaaa_t const *inst)
+{
+ int ret = ctx->inst[0].npc;
+ int dst = ctx->inst[0].npc + sex(inst->Imm, 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_execute_RET_1001010100001000(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_RET_1001010100001000_t const *inst)
+{
+ 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_execute_RETI_1001010100011000(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_RETI_1001010100011000_t const *inst)
+{
+ 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_execute_RJMP_1100aaaaaaaaaaaa(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_RJMP_1100aaaaaaaaaaaa_t const *inst)
+{
+ int dst = ctx->inst[0].npc + sex(inst->Imm, 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_execute_ROR_1001010aaaaa0111(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_ROR_1001010aaaaa0111_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rd];
+ 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_execute_SBC_000010abbbbbcccc(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_SBC_000010abbbbbcccc_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rd];
+ TCGv Rr = cpu_r[(inst->hRr << 4) | (inst->lRr)];
+ 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_execute_SBCI_0100aaaabbbbcccc(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_SBCI_0100aaaabbbbcccc_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rd];
+ TCGv Rr = tcg_const_i32((inst->hImm << 4) | inst->lImm);
+ 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;
+}
+
+
+/* Sets a specified bit in an I/O Register. This instruction operates on the lower 32 I/O Registers – addresses 0-31. */
+int avr_execute_SBI_10011010aaaaabbb(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_SBI_10011010aaaaabbb_t const *inst)
+{
+ TCGv data = cpu_io[inst->Imm];
+ TCGv port = tcg_const_i32(inst->Imm);
+
+ tcg_gen_ori_tl( data, data, 1 << inst->Bit);
+ gen_helper_outb(cpu_env,port, 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_execute_SBIC_10011001aaaaabbb(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_SBIC_10011001aaaaabbb_t const *inst)
+{
+ TCGv io = cpu_io[inst->Imm];
+ TCGv t0 = tcg_temp_new_i32();
+ TCGLabel *skip= gen_new_label();
+
+ tcg_gen_movi_tl( cpu_pc, ctx->inst[1].npc); /* PC if next inst is skipped */
+ tcg_gen_andi_tl( t0, io, 1 << inst->Bit);
+ tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, skip);
+ tcg_gen_movi_tl( cpu_pc, ctx->inst[0].npc); /* PC if next inst is not skipped */
+ gen_set_label(skip);
+
+ tcg_temp_free_i32(t0);
+
+ 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_execute_SBIS_10011011aaaaabbb(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_SBIS_10011011aaaaabbb_t const *inst)
+{
+ TCGv io = cpu_io[inst->Imm];
+ TCGv t0 = tcg_temp_new_i32();
+ TCGLabel *skip= gen_new_label();
+
+ tcg_gen_movi_tl( cpu_pc, ctx->inst[1].npc); /* PC if next inst is skipped */
+ tcg_gen_andi_tl( t0, io, 1 << inst->Bit);
+ tcg_gen_brcondi_i32(TCG_COND_NE, t0, 0, skip);
+ tcg_gen_movi_tl( cpu_pc, ctx->inst[0].npc); /* PC if next inst is not skipped */
+ gen_set_label(skip);
+
+ tcg_temp_free_i32(t0);
+
+ 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_execute_SBIW_10010111aabbcccc(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_SBIW_10010111aabbcccc_t const *inst)
+{
+ if (avr_feature(env, AVR_FEATURE_ADIW_SBIW) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv RdL = cpu_r[24 + 2 *inst->Rd];
+ TCGv RdH = cpu_r[25 + 2 *inst->Rd];
+ int Imm = (inst->hImm << 4) | (inst->lImm);
+ TCGv R = tcg_temp_new_i32();
+ TCGv Rd = tcg_temp_new_i32();
+ TCGv t0 = tcg_temp_new_i32();
+
+ /* op */
+ tcg_gen_shli_tl(Rd, RdH, 8); /* R = ((H << 8) | L) - Imm */
+ tcg_gen_or_tl( Rd, RdL, Rd);
+ tcg_gen_subi_tl(R, Rd, Imm);
+ tcg_gen_andi_tl(R, R, 0xffff);/* make it 16 bits */
+
+ /* Cf */
+ tcg_gen_not_tl( t0, R); /* t0 = Rd & ~R */
+ tcg_gen_and_tl( t0, Rd, t0);
+ tcg_gen_shri_tl(cpu_Cf, t0, 15); /* Cf = t0(15) */
+
+ /* Vf */
+ tcg_gen_not_tl( t0, Rd); /* t0 = ~Rd & R */
+ tcg_gen_and_tl( t0, R, t0);
+
+ tcg_gen_shri_tl(cpu_Vf, t0, 15); /* Vf = t0(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_and_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(t0);
+ 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_execute_SBRC_1111110aaaaa0bbb(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_SBRC_1111110aaaaa0bbb_t const *inst)
+{
+ TCGv Rr = cpu_r[inst->Rr];
+ TCGv t0 = tcg_temp_new_i32();
+ TCGLabel *skip= gen_new_label();
+
+ tcg_gen_movi_tl( cpu_pc, ctx->inst[1].npc); /* PC if next inst is skipped */
+ tcg_gen_andi_tl( t0, Rr, 1 << inst->Bit);
+ tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, skip);
+ tcg_gen_movi_tl( cpu_pc, ctx->inst[0].npc); /* PC if next inst is not skipped */
+ 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_execute_SBRS_1111111aaaaa0bbb(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_SBRS_1111111aaaaa0bbb_t const *inst)
+{
+ TCGv Rr = cpu_r[inst->Rr];
+ TCGv t0 = tcg_temp_new_i32();
+ TCGLabel *skip= gen_new_label();
+
+ tcg_gen_movi_tl( cpu_pc, ctx->inst[1].npc); /* PC if next inst is skipped */
+ tcg_gen_andi_tl( t0, Rr, 1 << inst->Bit);
+ tcg_gen_brcondi_i32(TCG_COND_NE, t0, 0, skip);
+ tcg_gen_movi_tl( cpu_pc, ctx->inst[0].npc); /* PC if next inst is not skipped */
+ 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_execute_SLEEP_1001010110001000(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_SLEEP_1001010110001000_t const *inst)
+{
+ 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_execute_SPM_1001010111101000(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_SPM_1001010111101000_t const *inst)
+{
+ if (avr_feature(env, AVR_FEATURE_SPM) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ /* TODO: ??? */
+ return BS_NONE;
+}
+
+int avr_execute_SPMX_1001010111111000(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_SPMX_1001010111111000_t const *inst)
+{
+ if (avr_feature(env, AVR_FEATURE_SPMX) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ /* TODO: ??? */
+ return BS_NONE;
+}
+
+int avr_execute_STX1_1001001aaaaa1100(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_STX1_1001001aaaaa1100_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rr];
+ TCGv addr= tcg_temp_new_i32();
+ TCGv H = cpu_rampX;
+ TCGv M = cpu_r[27];
+ TCGv L = cpu_r[26];
+
+ tcg_gen_mov_tl( addr, H); /* addr = H:M:L */
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, M);
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, L);
+
+ tcg_gen_qemu_st8(
+ Rd, addr, DATA_INDEX);
+
+ tcg_temp_free_i32(addr);
+
+
+ return BS_NONE;
+}
+
+int avr_execute_STX2_1001001aaaaa1101(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_STX2_1001001aaaaa1101_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rr];
+ TCGv addr= tcg_temp_new_i32();
+ TCGv H = cpu_rampX;
+ TCGv M = cpu_r[27];
+ TCGv L = cpu_r[26];
+
+ tcg_gen_mov_tl( addr, H); /* addr = H:M:L */
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, M);
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, L);
+
+ tcg_gen_qemu_st8(
+ Rd, addr, DATA_INDEX);
+ tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
+
+ tcg_gen_mov_tl( L, addr);
+ tcg_gen_andi_tl(L, L, 0xff);
+
+ tcg_gen_shri_tl(addr, addr, 8);
+ tcg_gen_mov_tl( M, addr);
+ tcg_gen_andi_tl(M, M, 0xff);
+
+ tcg_gen_shri_tl(addr, addr, 8);
+ tcg_gen_mov_tl( H, addr);
+ tcg_gen_andi_tl(H, H, 0xff);
+
+ tcg_temp_free_i32(addr);
+
+
+ return BS_NONE;
+}
+
+int avr_execute_STX3_1001001aaaaa1110(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_STX3_1001001aaaaa1110_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rr];
+ TCGv addr= tcg_temp_new_i32();
+ TCGv H = cpu_rampX;
+ TCGv M = cpu_r[27];
+ TCGv L = cpu_r[26];
+
+ tcg_gen_mov_tl( addr, H); /* addr = H:M:L */
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, M);
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, L);
+
+ tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */
+ tcg_gen_qemu_st8(
+ Rd, addr, DATA_INDEX);
+
+ tcg_gen_mov_tl( L, addr);
+ tcg_gen_andi_tl(L, L, 0xff);
+
+ tcg_gen_shri_tl(addr, addr, 8);
+ tcg_gen_mov_tl( M, addr);
+ tcg_gen_andi_tl(M, M, 0xff);
+
+ tcg_gen_shri_tl(addr, addr, 8);
+ tcg_gen_mov_tl( H, addr);
+ tcg_gen_andi_tl(H, H, 0xff);
+
+ tcg_temp_free_i32(addr);
+
+
+ return BS_NONE;
+}
+
+int avr_execute_STY2_1001001aaaaa1001(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_STY2_1001001aaaaa1001_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rd];
+ TCGv addr= tcg_temp_new_i32();
+ TCGv H = cpu_rampY;
+ TCGv M = cpu_r[29];
+ TCGv L = cpu_r[28];
+
+ tcg_gen_mov_tl( addr, H); /* addr = H:M:L */
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, M);
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, L);
+
+ tcg_gen_qemu_st8(
+ Rd, addr, DATA_INDEX);
+ tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
+
+ tcg_gen_mov_tl( L, addr);
+ tcg_gen_andi_tl(L, L, 0xff);
+
+ tcg_gen_shri_tl(addr, addr, 8);
+ tcg_gen_mov_tl( M, addr);
+ tcg_gen_andi_tl(M, M, 0xff);
+
+ tcg_gen_shri_tl(addr, addr, 8);
+ tcg_gen_mov_tl( H, addr);
+ tcg_gen_andi_tl(H, H, 0xff);
+
+ tcg_temp_free_i32(addr);
+
+
+ return BS_NONE;
+}
+
+int avr_execute_STY3_1001001aaaaa1010(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_STY3_1001001aaaaa1010_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rd];
+ TCGv addr= tcg_temp_new_i32();
+ TCGv H = cpu_rampY;
+ TCGv M = cpu_r[29];
+ TCGv L = cpu_r[28];
+
+ tcg_gen_mov_tl( addr, H); /* addr = H:M:L */
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, M);
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, L);
+
+ tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */
+ tcg_gen_qemu_st8(
+ Rd, addr, DATA_INDEX);
+
+ tcg_gen_mov_tl( L, addr);
+ tcg_gen_andi_tl(L, L, 0xff);
+
+ tcg_gen_shri_tl(addr, addr, 8);
+ tcg_gen_mov_tl( M, addr);
+ tcg_gen_andi_tl(M, M, 0xff);
+
+ tcg_gen_shri_tl(addr, addr, 8);
+ tcg_gen_mov_tl( H, addr);
+ tcg_gen_andi_tl(H, H, 0xff);
+
+ tcg_temp_free_i32(addr);
+
+
+ return BS_NONE;
+}
+
+int avr_execute_STDY_10a0bb1ccccc1ddd(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_STDY_10a0bb1ccccc1ddd_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rd];
+ TCGv addr= tcg_temp_new_i32();
+ TCGv H = cpu_rampY;
+ TCGv M = cpu_r[29];
+ TCGv L = cpu_r[28];
+
+ tcg_gen_mov_tl( addr, H); /* addr = H:M:L */
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, M);
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, L);
+
+ tcg_gen_addi_tl(addr, addr, (inst->hImm << 5) | (inst->mImm << 2) | inst->lImm);
+ /* addr = addr + q */
+ tcg_gen_qemu_st8(
+ Rd, addr, DATA_INDEX);
+
+ tcg_temp_free_i32(addr);
+
+
+ return BS_NONE;
+}
+
+int avr_execute_STZ2_1001001aaaaa0001(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_STZ2_1001001aaaaa0001_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rd];
+ TCGv addr= tcg_temp_new_i32();
+ TCGv H = cpu_rampZ;
+ TCGv M = cpu_r[31];
+ TCGv L = cpu_r[30];
+
+ tcg_gen_mov_tl( addr, H); /* addr = H:M:L */
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, M);
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, L);
+
+ tcg_gen_qemu_st8(
+ Rd, addr, DATA_INDEX);
+ tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
+
+ tcg_gen_mov_tl( L, addr);
+ tcg_gen_andi_tl(L, L, 0xff);
+
+ tcg_gen_shri_tl(addr, addr, 8);
+ tcg_gen_mov_tl( M, addr);
+ tcg_gen_andi_tl(M, M, 0xff);
+
+ tcg_gen_shri_tl(addr, addr, 8);
+ tcg_gen_mov_tl( H, addr);
+ tcg_gen_andi_tl(H, H, 0xff);
+
+ tcg_temp_free_i32(addr);
+
+
+
+ return BS_NONE;
+}
+
+int avr_execute_STZ3_1001001aaaaa0010(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_STZ3_1001001aaaaa0010_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rd];
+ TCGv addr= tcg_temp_new_i32();
+ TCGv H = cpu_rampZ;
+ TCGv M = cpu_r[31];
+ TCGv L = cpu_r[30];
+
+ tcg_gen_mov_tl( addr, H); /* addr = H:M:L */
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, M);
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, L);
+
+ tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */
+ tcg_gen_qemu_st8(
+ Rd, addr, DATA_INDEX);
+
+ tcg_gen_mov_tl( L, addr);
+ tcg_gen_andi_tl(L, L, 0xff);
+
+ tcg_gen_shri_tl(addr, addr, 8);
+ tcg_gen_mov_tl( M, addr);
+ tcg_gen_andi_tl(M, M, 0xff);
+
+ tcg_gen_shri_tl(addr, addr, 8);
+ tcg_gen_mov_tl( H, addr);
+ tcg_gen_andi_tl(H, H, 0xff);
+
+ tcg_temp_free_i32(addr);
+
+
+
+ return BS_NONE;
+}
+
+int avr_execute_STDZ_10a0bb1ccccc0ddd(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_STDZ_10a0bb1ccccc0ddd_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rd];
+ TCGv addr= tcg_temp_new_i32();
+ TCGv H = cpu_rampZ;
+ TCGv M = cpu_r[31];
+ TCGv L = cpu_r[30];
+
+ tcg_gen_mov_tl( addr, H); /* addr = H:M:L */
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, M);
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, L);
+
+ tcg_gen_addi_tl(addr, addr, (inst->hImm << 5) | (inst->mImm << 2) | inst->lImm);
+ /* addr = addr + q */
+ tcg_gen_qemu_st8(
+ Rd, addr, DATA_INDEX);
+
+ 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_execute_STS_1001001aaaaa0000bbbbbbbbbbbbbbbb(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_STS_1001001aaaaa0000bbbbbbbbbbbbbbbb_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rd];
+ 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, inst->Imm);
+
+ tcg_gen_qemu_st8(
+ Rd, addr, DATA_INDEX);
+
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+
+/* Subtracts two registers and places the result in the destination register Rd. */
+int avr_execute_SUB_000110abbbbbcccc(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_SUB_000110abbbbbcccc_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rd];
+ TCGv Rr = cpu_r[(inst->hRr << 4) | (inst->lRr)];
+ 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_execute_SUBI_0101aaaabbbbcccc(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_SUBI_0101aaaabbbbcccc_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rd];
+ TCGv Rr = tcg_const_i32((inst->hImm << 4) | inst->lImm);
+ 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_execute_SWAP_1001010aaaaa0010(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_SWAP_1001010aaaaa0010_t const *inst)
+{
+ TCGv Rd = cpu_r[inst->Rd];
+ TCGv t0 = tcg_temp_new_i32();
+ TCGv t1 = tcg_temp_new_i32();
+
+ tcg_gen_andi_tl(t0, Rd, 0x0f);
+ tcg_gen_shli_tl(t0, t0, 4);
+ tcg_gen_andi_tl(t1, Rd, 0xf0);
+ tcg_gen_shri_tl(t1, t1, 4);
+ tcg_gen_or_tl( Rd, t0, t1);
+
+ tcg_temp_free_i32(t1);
+ tcg_temp_free_i32(t0);
+
+ return 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_execute_WDR_1001010110101000(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_WDR_1001010110101000_t const *inst)
+{
+
+ 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_execute_XCH_1001001aaaaa0100(CPUAVRState *env, DisasContext *ctx,
+ avr_opcode_XCH_1001001aaaaa0100_t const *inst)
+{
+ if (avr_feature(env, AVR_FEATURE_RMW) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv Rd = cpu_r[inst->Rd];
+ TCGv t0 = tcg_temp_new_i32();
+ TCGv addr= tcg_temp_new_i32();
+ TCGv H = cpu_rampZ;
+ TCGv M = cpu_r[31];
+ TCGv L = cpu_r[30];
+
+ tcg_gen_mov_tl( addr, H); /* addr = rampZ:r31:r30 */
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, M);
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl( addr, addr, L);
+
+ tcg_gen_qemu_ld8u(
+ addr, t0, DATA_INDEX);
+ tcg_gen_qemu_st8(
+ addr, Rd, DATA_INDEX);
+ tcg_gen_mov_tl( Rd, t0);
+
+ tcg_temp_free_i32(t0);
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
--
2.4.9 (Apple Git-60)
next reply other threads:[~2016-05-29 8:58 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-05-29 8:57 Michael Rolnik [this message]
2016-05-29 12:45 ` [Qemu-devel] Initial commit of AVR cores Peter Maydell
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='CAK4993gh8De=RsYfPdhN31Rv=1vUCBaQceSeMsZFH2-iwr-kig@mail.gmail.com' \
--to=mrolnik@gmail.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).