Re: [Qemu-devel] [PATCH v21 4/7] target/avr: Add instruction translation

2019-06-12 Thread Richard Henderson
On 6/11/19 2:02 PM, Michael Rolnik wrote:
> I am using this
> one 
> https://github.com/seharris/qemu-avr-tests/blob/master/free-rtos/Demo/AVR_ATMega2560_GCC/demo.elf
> 
>  
> it fails within __divmodsi4 function, there is rcall right after sbrc.
> 
> Thanks for helping.

Two separate bugs, fixed thus.


r~
>From 7be2c4dfcbdca59f6b5b52f65f3fc1df6923db50 Mon Sep 17 00:00:00 2001
From: Richard Henderson 
Date: Wed, 12 Jun 2019 09:31:14 -0700
Subject: [PATCH] !fixup target/avr: Add instruction translation

When skipping, the skipped NORETURN must chain to the next.
Avoid double-allocating goto_tb indexes.  Choose index 1 to
be the end of TB, which means all other branches use 0.
---
 target/avr/translate.c | 9 ++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/target/avr/translate.c b/target/avr/translate.c
index 4d9e2afa26..abb838b53f 100644
--- a/target/avr/translate.c
+++ b/target/avr/translate.c
@@ -622,7 +622,7 @@ static bool trans_BRBC(DisasContext *ctx, arg_BRBC *a)
 }
 
 tcg_gen_brcondi_i32(tcg_invert_cond(cond), var, 0, not_taken);
-gen_goto_tb(ctx, 1, ctx->npc + a->imm);
+gen_goto_tb(ctx, 0, ctx->npc + a->imm);
 gen_set_label(not_taken);
 
 ctx->bstate = DISAS_CHAIN;
@@ -672,7 +672,7 @@ static bool trans_BRBS(DisasContext *ctx, arg_BRBS *a)
 }
 
 tcg_gen_brcondi_i32(tcg_invert_cond(cond), var, 0, not_taken);
-gen_goto_tb(ctx, 1, ctx->npc + a->imm);
+gen_goto_tb(ctx, 0, ctx->npc + a->imm);
 gen_set_label(not_taken);
 
 ctx->bstate = DISAS_CHAIN;
@@ -2855,6 +2855,9 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns)
 if (skip_label) {
 canonicalize_skip();
 gen_set_label(skip_label);
+if (ctx.bstate == DISAS_NORETURN) {
+ctx.bstate = DISAS_CHAIN;
+}
 }
 } while (ctx.bstate == DISAS_NEXT
  && num_insns < max_insns
@@ -2876,7 +2879,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns)
 case DISAS_CHAIN:
 if (!nonconst_skip) {
 /* Note gen_goto_tb checks singlestep.  */
-gen_goto_tb(, 0, ctx.npc);
+gen_goto_tb(, 1, ctx.npc);
 break;
 }
 tcg_gen_movi_tl(cpu_pc, ctx.npc);
-- 
2.17.1



Re: [Qemu-devel] [PATCH v21 4/7] target/avr: Add instruction translation

2019-06-11 Thread Michael Rolnik
I am using this one
https://github.com/seharris/qemu-avr-tests/blob/master/free-rtos/Demo
/AVR_ATMega2560_GCC/demo.elf
it fails within __divmodsi4 function, there is rcall right after sbrc.

Thanks for helping.

On Tue, Jun 11, 2019 at 11:47 PM Richard Henderson <
richard.hender...@linaro.org> wrote:

> On 6/11/19 1:21 PM, Michael Rolnik wrote:
> > I merged all you fixes and I get an assert(use_icount)
> in cpu_loop_exec_tb
> > function, it happens on an instruction following SBRC.
> > what might cause it?
>
> No idea.  What is your test case?  And your tree, just in case there was an
> error in the merging.
>
> Looking through output from
>
>   qemu-avr-tests/instruction-tests/bin/SBR.elf
>
>  14a:   00 fc   sbrcr0, 0
>  14c:   0f ef   ldi r16, 0xFF   ; 255
>
> it works for me:
>
>   00a5
>  movi_i32 tmp2,$0x1
>  and_i32 tmp1,r0,tmp2
>
>   00a6
>  movi_i32 tmp2,$0x0
>  brcond_i32 tmp1,tmp2,eq,$L1
>  movi_i32 r16,$0xff
>  set_label $L1
>
>
> r~
>


-- 
Best Regards,
Michael Rolnik


Re: [Qemu-devel] [PATCH v21 4/7] target/avr: Add instruction translation

2019-06-11 Thread Richard Henderson
On 6/11/19 1:21 PM, Michael Rolnik wrote:
> I merged all you fixes and I get an assert(use_icount) in cpu_loop_exec_tb
> function, it happens on an instruction following SBRC.
> what might cause it?

No idea.  What is your test case?  And your tree, just in case there was an
error in the merging.

Looking through output from

  qemu-avr-tests/instruction-tests/bin/SBR.elf

 14a:   00 fc   sbrcr0, 0
 14c:   0f ef   ldi r16, 0xFF   ; 255

it works for me:

  00a5
 movi_i32 tmp2,$0x1
 and_i32 tmp1,r0,tmp2

  00a6
 movi_i32 tmp2,$0x0
 brcond_i32 tmp1,tmp2,eq,$L1
 movi_i32 r16,$0xff
 set_label $L1


r~



Re: [Qemu-devel] [PATCH v21 4/7] target/avr: Add instruction translation

2019-06-11 Thread Michael Rolnik
Hi Richard.

I merged all you fixes and I get an assert(use_icount) in cpu_loop_exec_tb
function, it happens on an instruction following SBRC.
what might cause it?

On Tue, Jun 11, 2019 at 12:20 AM Richard Henderson <
richard.hender...@linaro.org> wrote:

> On 6/6/19 12:30 PM, Michael Rolnik wrote:
> > +if (ctx.check_skip > 0) {
> > +TCGLabel *skip = gen_new_label();
> > +TCGLabel *done = gen_new_label();
> > +
> > +tcg_gen_brcondi_tl(TCG_COND_NE, cpu_skip, 0, skip);
> > +translate();
> > +tcg_gen_br(done);
> > +gen_set_label(skip);
> > +tcg_gen_movi_tl(cpu_skip, 0);
> > +tcg_gen_movi_tl(cpu_pc, ctx.npc);
> > +gen_set_label(done);
> > +ctx.check_skip--;
> > +} else {
> > +translate();
> > +}
>
> In future, do not indent code like this.
>
> I had been thinking of a slightly more complex solution that does not
> require
> every TB to begin with a conditional branch testing cpu_skip.  This also
> has
> the property that we almost never write to cpu_skip at all -- the
> condition is
> consumed immediately within host registers without being written back to
> ENV.
> The only time we do write to cpu_skip is for debugging, single-stepping, or
> when we are forced to break the TB for other unusual reasons.
>
> The following implements this solution.  It's based on some other cleanups
> that
> I have made, and commented upon here.  The full tree can be found at
>
>   https://github.com/rth7680/qemu/commits/review/avr-21
>
>
> r~
>


-- 
Best Regards,
Michael Rolnik


Re: [Qemu-devel] [PATCH v21 4/7] target/avr: Add instruction translation

2019-06-10 Thread Richard Henderson
On 6/6/19 12:30 PM, Michael Rolnik wrote:
> +if (ctx.check_skip > 0) {
> +TCGLabel *skip = gen_new_label();
> +TCGLabel *done = gen_new_label();
> +
> +tcg_gen_brcondi_tl(TCG_COND_NE, cpu_skip, 0, skip);
> +translate();
> +tcg_gen_br(done);
> +gen_set_label(skip);
> +tcg_gen_movi_tl(cpu_skip, 0);
> +tcg_gen_movi_tl(cpu_pc, ctx.npc);
> +gen_set_label(done);
> +ctx.check_skip--;
> +} else {
> +translate();
> +}

In future, do not indent code like this.

I had been thinking of a slightly more complex solution that does not require
every TB to begin with a conditional branch testing cpu_skip.  This also has
the property that we almost never write to cpu_skip at all -- the condition is
consumed immediately within host registers without being written back to ENV.
The only time we do write to cpu_skip is for debugging, single-stepping, or
when we are forced to break the TB for other unusual reasons.

The following implements this solution.  It's based on some other cleanups that
I have made, and commented upon here.  The full tree can be found at

  https://github.com/rth7680/qemu/commits/review/avr-21


r~
>From 893b021bc042c5cb5e7d9cf7d6ff3d9e2cfc25de Mon Sep 17 00:00:00 2001
From: Richard Henderson 
Date: Sun, 9 Jun 2019 21:38:38 -0700
Subject: [PATCH] !fixup target/avr: Add instruction translation

Reorganize instruction skipping.

Put the known state of env->skip into TBFLAGS, which allows the
first instruction to not test cpu_skip directly.  It either knows
that we need not skip (almost always), or that we must skip (rarely).

Put the in-flight skipping state into tcg variables.  This allows
us to consume the skip state without writing it out to cpu_skip.
---
 target/avr/cpu.h   |   4 +
 target/avr/translate.c | 248 +++--
 2 files changed, 167 insertions(+), 85 deletions(-)

diff --git a/target/avr/cpu.h b/target/avr/cpu.h
index a086aca30c..a0de72d75b 100644
--- a/target/avr/cpu.h
+++ b/target/avr/cpu.h
@@ -187,6 +187,7 @@ int avr_cpu_memory_rw_debug(CPUState *cs, vaddr address, uint8_t *buf,
 
 enum {
 TB_FLAGS_FULL_ACCESS = 1,
+TB_FLAGS_SKIP = 2,
 };
 
 static inline void cpu_get_tb_cpu_state(CPUAVRState *env, target_ulong *pc,
@@ -200,6 +201,9 @@ static inline void cpu_get_tb_cpu_state(CPUAVRState *env, target_ulong *pc,
 if (env->fullacc) {
 flags |= TB_FLAGS_FULL_ACCESS;
 }
+if (env->skip) {
+flags |= TB_FLAGS_SKIP;
+}
 
 *pflags = flags;
 }
diff --git a/target/avr/translate.c b/target/avr/translate.c
index dd22abf93a..4d9e2afa26 100644
--- a/target/avr/translate.c
+++ b/target/avr/translate.c
@@ -78,7 +78,11 @@ struct DisasContext {
 int memidx;
 int bstate;
 int singlestep;
-int check_skip;
+
+TCGv skip_var0;
+TCGv skip_var1;
+TCGCond skip_cond;
+bool free_skip_var0;
 };
 
 static int to_A(DisasContext *ctx, int indx) { return 16 + (indx % 16); }
@@ -583,38 +587,45 @@ static bool trans_BLD(DisasContext *ctx, arg_BLD *a)
  */
 static bool trans_BRBC(DisasContext *ctx, arg_BRBC *a)
 {
-TCGLabel *taken = gen_new_label();
+TCGLabel *not_taken = gen_new_label();
+TCGCond cond = TCG_COND_EQ;
+TCGv var;
 
 switch (a->bit) {
 case 0x00:
-tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_Cf, 0, taken);
+var = cpu_Cf;
 break;
 case 0x01:
-tcg_gen_brcondi_i32(TCG_COND_NE, cpu_Zf, 0, taken);
+cond = TCG_COND_NE;
+var = cpu_Zf;
 break;
 case 0x02:
-tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_Nf, 0, taken);
+var = cpu_Nf;
 break;
 case 0x03:
-tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_Vf, 0, taken);
+var = cpu_Vf;
 break;
 case 0x04:
-tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_Sf, 0, taken);
+var = cpu_Sf;
 break;
 case 0x05:
-tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_Hf, 0, taken);
+var = cpu_Hf;
 break;
 case 0x06:
-tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_Tf, 0, taken);
+var = cpu_Tf;
 break;
 case 0x07:
-tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_If, 0, taken);
+var = cpu_If;
 break;
+default:
+g_assert_not_reached();
 }
 
-gen_goto_tb(ctx, 1, ctx->npc);
-gen_set_label(taken);
-gen_goto_tb(ctx, 0, ctx->npc + a->imm);
+tcg_gen_brcondi_i32(tcg_invert_cond(cond), var, 0, not_taken);
+gen_goto_tb(ctx, 1, ctx->npc + a->imm);
+gen_set_label(not_taken);
+
+ctx->bstate = DISAS_CHAIN;
 return true;
 }
 
@@ -626,38 +637,45 @@ static bool trans_BRBC(DisasContext *ctx, arg_BRBC *a)
  */
 static bool trans_BRBS(DisasContext *ctx, arg_BRBS *a)
 {
-TCGLabel *taken = gen_new_label();
+TCGLabel *not_taken = gen_new_label();
+TCGCond cond = TCG_COND_NE;
+TCGv var;
 
 switch 

Re: [Qemu-devel] [PATCH v21 4/7] target/avr: Add instruction translation

2019-06-10 Thread Richard Henderson
On 6/6/19 12:30 PM, Michael Rolnik wrote:
> +if ((ctx.cpc & (TARGET_PAGE_SIZE - 1)) == 0) {
> +break; /* page boundary */
> +}

This test isn't right, because this ended the TB if the *first* instruction was
located on the page boundary.  It also fails to allow for a 32-bit opcode to
span 0xff - 0x101, since we did not see an instruction boundary at 0x100.

Since there is no MMU, we do not have to protect against permissions changes.
All we have to worry about is QEMU's code that detects self-modifying code.
This requires the code for each TranslationBlocks be contained within no more
than two pages.  Therefore,

/* Do not allow the next insn to cross into a third code page.  */
if ((ctx.npc - pc_start) * 2 >= TARGET_PAGE_SIZE - 4) {
break;
}

is the better condition.  Subtracting 4 allows for the next instruction to be a
32-bit opcode.  Limiting to TARGET_PAGE_SIZE allows pc_start to be located
anywhere in the first code page without allowing npc to cross into a third code
page.


r~



Re: [Qemu-devel] [PATCH v21 4/7] target/avr: Add instruction translation

2019-06-10 Thread Richard Henderson
On 6/6/19 12:30 PM, Michael Rolnik wrote:
> +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 */
> +};

This set of exit conditions is confused and incomplete.

(1) BS_BRANCH and BS_EXCP do the same thing, namely they
equate exactly to DISAS_NORETURN.

(2) BS_NONE equates exactly to DISAS_NEXT.

(3) BS_STOP is probably better named DISAS_EXIT, just so
it matches the other naming above, and that it will
result in a call to tcg_gen_exit_tb.

(4) You're missing a case that applies to indirect branches
which should use tcg_gen_lookup_and_goto_tb().
I suggest this be called DISAS_LOOKUP.

> +static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
> +{
> +TranslationBlock *tb = ctx->tb;
> +
> +if (ctx->singlestep == 0) {
> +tcg_gen_goto_tb(n);
> +tcg_gen_movi_i32(cpu_pc, dest);
> +tcg_gen_exit_tb(tb, n);
> +} else {
> +tcg_gen_movi_i32(cpu_pc, dest);
> +gen_helper_debug(cpu_env);
> +tcg_gen_exit_tb(NULL, 0);
> +}
> +}

Should set ctx->bstate = DISAS_NORETURN here, and not to BS_BRANCH in the 
callers.

> +if (avr_feature(ctx->env, AVR_FEATURE_ADIW_SBIW) == false) {
> +gen_helper_unsupported(cpu_env);
> +
> +ctx->bstate = BS_EXCP;
> +return true;
> +}

It would be good to define a helper function

static bool have_feature(DisasContext *ctx, int feature)
{
if (!avr_feature(ctx->env, feature)) {
gen_helper_unsupported(cpu_env);
ctx->bstate = DISAS_NORETURN;
return false;
}
return true;
}

so that this pattern becomes

if (!have_feature(ctx, AVR_FEATURE_FOO)) {
return true;
}
// Lots of code
return true;

or

if (have_feature(ctx, AVR_FEATURE_FOO)) {
// Just a few lines
}
return true;

> +/*
> + *  Returns from subroutine. The return address is loaded from the STACK.
> + *  The Stack Pointer uses a preincrement scheme during RET.
> + */
> +static bool trans_RET(DisasContext *ctx, arg_RET *a)
> +{
> +gen_pop_ret(ctx, cpu_pc);
> +
> +tcg_gen_exit_tb(NULL, 0);
> +
> +ctx->bstate = BS_BRANCH;
> +return true;
> +}

With very few exceptions, the lone use of tcg_gen_exit_tb is a bug, because you
have failed to take ctx->singlestep into account.

In this case, this is one of the indirect branch places which you should be
using DISAS_LOOKUP.

> +static bool trans_RETI(DisasContext *ctx, arg_RETI *a)
> +{
> +gen_pop_ret(ctx, cpu_pc);
> +
> +tcg_gen_movi_tl(cpu_If, 1);
> +
> +tcg_gen_exit_tb(NULL, 0);
> +
> +ctx->bstate = BS_BRANCH;
> +return true;
> +}

Here you need to use DISAS_EXIT, because instructions that enable interrupts
also need to exit to the main loop so that we re-evaluate whether interrupts
need to be delivered.

> +if (ctx.singlestep) {
> +if (ctx.bstate == BS_STOP || ctx.bstate == BS_NONE) {
> +tcg_gen_movi_tl(cpu_pc, ctx.npc);
> +}
> +gen_helper_debug(cpu_env);
> +tcg_gen_exit_tb(NULL, 0);
> +} else {
> +switch (ctx.bstate) {
> +case BS_STOP:
> +case BS_NONE:
> +gen_goto_tb(, 0, ctx.npc);
> +break;
> +case BS_EXCP:
> +case BS_BRANCH:
> +tcg_gen_exit_tb(NULL, 0);
> +break;
> +default:
> +break;
> +}
> +}

Better written as

switch (ctx.bstate) {
case DISAS_NORETURN:
break;
case DISAS_NEXT:
case DISAS_CHAIN:
/* Note gen_goto_tb checks singlestep. */
gen_goto_tb(, 0, ctx.npc);
break;
case DISAS_LOOKUP:
if (!ctx.singlestep) {
tcg_gen_lookup_and_goto_ptr();
break;
}
/* fall through */
case DISAS_EXIT:
if (ctx.singlestep) {
gen_helper_debug(cpu_env);
} else {
tcg_gen_exit_tb(NULL, 0);
}
break;
default:
g_assert_not_reached();
}


r~



Re: [Qemu-devel] [PATCH v21 4/7] target/avr: Add instruction translation

2019-06-10 Thread Richard Henderson
On 6/6/19 12:30 PM, Michael Rolnik wrote:
> +target_long cpc;
> +target_long npc;

CPC gets copied back and forth to NPC, but is now otherwise unused.
You can drop that.

> +static void translate(DisasContext *ctx)
> +{
> +uint32_t opcode;
> +int res;
> +/* PC points to words.  */
> +opcode = cpu_ldl_code(ctx->env, ctx->cpc * 2) & 0x;
> +
> +ctx->npc = ctx->cpc + 1;

Which allows this to become

uint32_t opcode = next_word(ctx);


r~



Re: [Qemu-devel] [PATCH v21 4/7] target/avr: Add instruction translation

2019-06-10 Thread Richard Henderson
On 6/6/19 12:30 PM, Michael Rolnik wrote:
> +void avr_cpu_tcg_init(void)
> +{
> +int i;
> +
> +#define AVR_REG_OFFS(x) offsetof(CPUAVRState, x)
> +cpu_pc = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(pc_w), "pc");
> +cpu_Cf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregC), "Cf");
> +cpu_Zf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregZ), "Zf");
> +cpu_Nf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregN), "Nf");
> +cpu_Vf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregV), "Vf");
> +cpu_Sf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregS), "Sf");
> +cpu_Hf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregH), "Hf");
> +cpu_Tf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregT), "Tf");
> +cpu_If = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregI), "If");
> +cpu_rampD = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(rampD), 
> "rampD");
> +cpu_rampX = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(rampX), 
> "rampX");
> +cpu_rampY = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(rampY), 
> "rampY");
> +cpu_rampZ = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(rampZ), 
> "rampZ");
> +cpu_eind = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(eind), "eind");
> +cpu_sp = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sp), "sp");
> +cpu_skip = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(skip), "skip");
> +
> +for (i = 0; i < 32; i++) {
> +char name[16];
> +
> +sprintf(name, "r[%d]", i);
> +
> +cpu_r[i] = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(r[i]), name);
> +}
> +}

These register names need to be permanently allocated.
I suggest

static const char reg_names[32][8] = {
"r[0]", "r[1]" ...
};
cpu_r[i] = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(r[i]),
  reg_names[i]);


r~



[Qemu-devel] [PATCH v21 4/7] target/avr: Add instruction translation

2019-06-06 Thread Michael Rolnik
From: Sarah Harris 

This includes:
- TCG translations for each instruction

Signed-off-by: Michael Rolnik 
---
 target/avr/translate.c | 2937 
 1 file changed, 2937 insertions(+)
 create mode 100644 target/avr/translate.c

diff --git a/target/avr/translate.c b/target/avr/translate.c
new file mode 100644
index 00..03b1a344cb
--- /dev/null
+++ b/target/avr/translate.c
@@ -0,0 +1,2937 @@
+/*
+ * 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
+ * 
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/qemu-print.h"
+#include "tcg/tcg.h"
+#include "cpu.h"
+#include "exec/exec-all.h"
+#include "disas/disas.h"
+#include "tcg-op.h"
+#include "exec/cpu_ldst.h"
+#include "exec/helper-proto.h"
+#include "exec/helper-gen.h"
+#include "exec/log.h"
+#include "exec/gdbstub.h"
+#include "exec/translator.h"
+
+static TCGv cpu_pc;
+
+static TCGv cpu_Cf;
+static TCGv cpu_Zf;
+static TCGv cpu_Nf;
+static TCGv cpu_Vf;
+static TCGv cpu_Sf;
+static TCGv cpu_Hf;
+static TCGv cpu_Tf;
+static TCGv cpu_If;
+
+static TCGv cpu_rampD;
+static TCGv cpu_rampX;
+static TCGv cpu_rampY;
+static TCGv cpu_rampZ;
+
+static TCGv cpu_r[32];
+static TCGv cpu_eind;
+static TCGv cpu_sp;
+
+static TCGv cpu_skip;
+
+#define REG(x) (cpu_r[x])
+
+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 */
+};
+
+typedef struct DisasContext DisasContext;
+
+/* This is the state at translation time. */
+struct DisasContext {
+TranslationBlock *tb;
+
+CPUAVRState *env;
+CPUState *cs;
+
+target_long cpc;
+target_long npc;
+uint32_t opcode;
+
+/* Routine used to access memory */
+int memidx;
+int bstate;
+int singlestep;
+int check_skip;
+};
+
+static int to_A(DisasContext *ctx, int indx) { return 16 + (indx % 16); }
+static int to_B(DisasContext *ctx, int indx) { return 16 + (indx % 8); }
+static int to_C(DisasContext *ctx, int indx) { return 24 + (indx % 4) * 2; }
+static int to_D(DisasContext *ctx, int indx) { return (indx % 16) * 2; }
+
+static uint16_t next_word(DisasContext *ctx)
+{
+return cpu_lduw_code(ctx->env, ctx->npc++ * 2);
+}
+
+static int append_16(DisasContext *ctx, int x)
+{
+return x << 16 | next_word(ctx);
+}
+
+static bool decode_insn(DisasContext *ctx, uint16_t insn);
+#include "decode_insn.inc.c"
+
+static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
+{
+TranslationBlock *tb = ctx->tb;
+
+if (ctx->singlestep == 0) {
+tcg_gen_goto_tb(n);
+tcg_gen_movi_i32(cpu_pc, dest);
+tcg_gen_exit_tb(tb, n);
+} else {
+tcg_gen_movi_i32(cpu_pc, dest);
+gen_helper_debug(cpu_env);
+tcg_gen_exit_tb(NULL, 0);
+}
+}
+
+#include "exec/gen-icount.h"
+
+static void gen_add_CHf(TCGv R, TCGv Rd, TCGv Rr)
+{
+TCGv t1 = tcg_temp_new_i32();
+TCGv t2 = tcg_temp_new_i32();
+TCGv t3 = tcg_temp_new_i32();
+
+tcg_gen_and_tl(t1, Rd, Rr); /* t1 = Rd & Rr */
+tcg_gen_andc_tl(t2, Rd, R); /* t2 = Rd & ~R */
+tcg_gen_andc_tl(t3, Rr, R); /* t3 = Rr & ~R */
+tcg_gen_or_tl(t1, t1, t2); /* t1 = t1 | t2 | t3 */
+tcg_gen_or_tl(t1, t1, t3);
+
+tcg_gen_shri_tl(cpu_Cf, t1, 7); /* Cf = t1(7) */
+tcg_gen_shri_tl(cpu_Hf, t1, 3); /* Hf = t1(3) */
+tcg_gen_andi_tl(cpu_Hf, cpu_Hf, 1);
+
+tcg_temp_free_i32(t3);
+tcg_temp_free_i32(t2);
+tcg_temp_free_i32(t1);
+}
+
+static void gen_add_Vf(TCGv R, TCGv Rd, TCGv Rr)
+{
+TCGv t1 = tcg_temp_new_i32();
+TCGv t2 = tcg_temp_new_i32();
+
+/* t1 = Rd & Rr & ~R | ~Rd & ~Rr & R = (Rd ^ R) & ~(Rd ^ Rr) */
+tcg_gen_xor_tl(t1, Rd, R);
+tcg_gen_xor_tl(t2, Rd, Rr);
+tcg_gen_andc_tl(t1, t1, t2);
+
+tcg_gen_shri_tl(cpu_Vf, t1, 7); /* Vf = t1(7) */
+
+tcg_temp_free_i32(t2);
+tcg_temp_free_i32(t1);
+}
+
+static void gen_sub_CHf(TCGv R, TCGv Rd, TCGv Rr)
+{
+TCGv t1 = tcg_temp_new_i32();
+TCGv t2 = tcg_temp_new_i32();
+TCGv t3 = tcg_temp_new_i32();
+
+/* Cf & Hf */
+tcg_gen_not_tl(t1, Rd); /* t1 = ~Rd */
+tcg_gen_and_tl(t2, t1, Rr); /* t2 = ~Rd & Rr */
+tcg_gen_or_tl(t3, t1, Rr); /* t3 = (~Rd | Rr)