diff mbox

[01/10] target-avr: AVR cores support is added. 1. basic CPU structure 2. registers 3. no instructions

Message ID 1464898022-97990-1-git-send-email-rolnik@amazon.com
State New
Headers show

Commit Message

Michael Rolnik June 2, 2016, 8:06 p.m. UTC
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 ++
 include/disas/bfd.h             |   7 +
 include/sysemu/arch_init.h      |   1 +
 target-avr/Makefile.objs        |   3 +
 target-avr/cpu-qom.h            |  97 +++++++++++++
 target-avr/cpu.c                | 315 ++++++++++++++++++++++++++++++++++++++++
 target-avr/cpu.h                | 152 +++++++++++++++++++
 target-avr/gdbstub.c            | 105 ++++++++++++++
 target-avr/helper.c             | 105 ++++++++++++++
 target-avr/helper.h             |  21 +++
 target-avr/machine.c            |  54 +++++++
 target-avr/machine.h            |  21 +++
 target-avr/translate.c          | 300 ++++++++++++++++++++++++++++++++++++++
 17 files changed, 1200 insertions(+)
 create mode 100644 default-configs/avr-softmmu.mak
 create mode 100644 disas/avr.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/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

Comments

Richard Henderson June 4, 2016, 7:55 p.m. UTC | #1
On 06/02/2016 01:06 PM, Michael Rolnik wrote:
> 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;
> +}

Since you never fill in this stub, drop it.  There is already a fall-back in 
disas.c if there is no printer for the guest.

> +void                avr_cpu_do_interrupt(
> +                                CPUState           *cpu);

One more time: bad formatting.

I don't know what you're trying to accomplish with aligning all of these 
arguments and function names, but you may have noticed that we do this no where 
else in qemu.

Personally, I find all this extra whitespace hard to read.

Finally, you really do need to fix all of the warnings that checkpatch.pl 
generates.  There are 80 ERRORs and 433 WARNINGs in this patch set.


> +static void         avr_cpu_reset(
> +                                CPUState           *s)
> +{
> +    AVRCPU         *cpu = AVR_CPU(s);
> +    AVRCPUClass    *mcc = AVR_CPU_GET_CLASS(cpu);
> +    CPUAVRState    *env = &cpu->env;
> +
> +    mcc->parent_reset(s);
> +
> +    memset(env, 0, sizeof(CPUAVRState));

Normally one doesn't clear anything past "features".  In particular, the stuff 
in CPU_COMMON may need to stay as-is.

> +#define TARGET_IS_LIENDIAN 1

Typo for BIENDIAN?

> +#define CODE_INDEX                  0
> +#define DATA_INDEX                  1

Better to use the standard naming, MMU_FOO_IDX.

> +static inline int   cpu_mmu_index(
> +                                CPUAVRState        *env,
> +                                bool                ifetch)
> +{
> +    return  0;
> +}

Probably returning MMU_DATA_IDX would be more intelligable.

> +static inline void  cpu_get_tb_cpu_state(
> +                                CPUAVRState        *env,
> +                                target_ulong       *pc,
> +                                target_ulong       *cs_base,
> +                                uint32_t           *pflags)
> +{
> +    *pc         = env->pc * 2;

I wonder if it would be helpful to change the name of env->pc so as to 
emphasize that it's a word address.  Otherwise these conversions can be confusing.

Perhaps

   *pc_b = env->pc_w * 2;

>     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         */
...
> static inline int cpu_interrupts_enabled(CPUAVRState *env1)
> {
>     return  env1->sregI != 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;
...
>         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;

Consider putting these into functions.  Compare the target-arm functions 
pstate_read and pstate_write.

You should also decide if you're going to canonicalize on a single bit set in 
these variables or not.  If they're always set via a mask, as above, then you 
don't need to mask again when you read, nor do you need to compare vs 0 when 
testing.

> +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);

If there's no virtual memory, why do you set TARGET_PAGE_BITS so low?

Performance of qemu itself is better with a larger page size.  Indeed, setting 
it to the gcd of allowable ram sizes would produce the minimum number of tlb 
entries.

> +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);
> +    }

Since you have no paging, you don't need to worry about chains crossing pages. 
Therefore this can be simplified to

     if (ctx->singlestep) {
         tcg_gen_movi_i32(cpu_pc, dest);
         gen_helper_debug(cpu_env);
     } else {
         tcg_gen_goto_tb(n);
         tcg_gen_movi_i32(cpu_pc, dest);
         tcg_gen_exit_tb((uintptr_t)tb + n);
     }

> +    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]);

Surely we can print this in a more compact form.

> +    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",

A more compact form for this would be

     "SREG: [ %c %c %c %c %c %c %c %c ]"
     env->sregI ? 'I' : '-',
     ...


r~
diff mbox

Patch

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/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..c503546
--- /dev/null
+++ b/target-avr/Makefile.objs
@@ -0,0 +1,3 @@ 
+obj-y   += translate.o cpu.o helper.o
+obj-y   += gdbstub.o
+obj-$(CONFIG_SOFTMMU) += machine.o
diff --git a/target-avr/cpu-qom.h b/target-avr/cpu-qom.h
new file mode 100644
index 0000000..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..ff26018
--- /dev/null
+++ b/target-avr/cpu.c
@@ -0,0 +1,315 @@ 
+/*
+ * 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;    /*  internaly PC points to words, not bytes */
+}
+
+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;
+
+    mcc->parent_reset(s);
+
+    memset(env, 0, sizeof(CPUAVRState));
+    env->pc         = 0;
+    env->sregI      = 1;
+
+    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_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 = "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..3692329
--- /dev/null
+++ b/target-avr/cpu.h
@@ -0,0 +1,152 @@ 
+/*
+ * 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
+
+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   */
+
+    /* Those resources are used only in QEMU core */
+    CPU_COMMON
+};
+
+#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/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..aec37af
--- /dev/null
+++ b/target-avr/helper.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 "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)
+{
+    return  false;
+}
+
+void                avr_cpu_do_interrupt(
+                                CPUState           *cs)
+{
+}
+
+int                 avr_cpu_memory_rw_debug(
+                                CPUState           *cs,
+                                vaddr               addr,
+                                uint8_t            *buf,
+                                int                 len,
+                                bool                is_write)
+{
+    return  cpu_memory_rw_debug(cs, addr, buf, len, is_write);
+}
+
+hwaddr              avr_cpu_get_phys_page_debug(
+                                CPUState           *cs,
+                                vaddr               addr)
+{
+    return  addr;   /*  I assume 1:1 address correspondance */
+}
+
+int                 avr_cpu_handle_mmu_fault(
+                                CPUState           *cs,
+                                vaddr               address,
+                                int                 rw,
+                                int                 mmu_idx)
+{
+    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);
+}
+
+void                helper_debug(
+                                CPUAVRState        *env)
+{
+    CPUState   *cs = CPU(avr_env_get_cpu(env));
+
+    cs->exception_index = EXCP_DEBUG;
+    cpu_loop_exit(cs);
+}
+
diff --git a/target-avr/helper.h b/target-avr/helper.h
new file mode 100644
index 0000000..017e076
--- /dev/null
+++ b/target-avr/helper.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>
+ */
+
+DEF_HELPER_1(debug,         void,   env)
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..e98aaef
--- /dev/null
+++ b/target-avr/translate.c
@@ -0,0 +1,300 @@ 
+/*
+ *  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"
+
+typedef struct DisasContext DisasContext;
+typedef struct InstInfo     InstInfo;
+
+/*This is the state at translation time.  */
+struct DisasContext {
+    struct TranslationBlock    *tb;
+
+    /*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);
+    }
+}
+
+/*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    */
+    cpc = pc_start;
+    npc = cpc + 1;
+    do {
+        /*  translate current instruction   */
+        tcg_gen_insn_start(cpc);
+        num_insns++;
+
+        /*  just skip to next instruction   */
+        cpc++;
+        npc++;
+        ctx.bstate  = BS_NONE;
+
+        if (unlikely(cpu_breakpoint_test(cs, cpc * 2, 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;
+        }
+
+        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 */
+        }
+    } 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");
+        }
+    }
+}