#include "exec/helper-gen.h"
#include "exec/log.h"
#include "exec/translator.h"
-#include "exec/gen-icount.h"
+
+#define HELPER_H "helper.h"
+#include "exec/helper-info.c.inc"
+#undef HELPER_H
+
/*
* Define if you want a BREAK instruction translated to a breakpoint
};
#define REG(x) (cpu_r[x])
-enum {
- DISAS_EXIT = DISAS_TARGET_0, /* We want return to the cpu main loop. */
- DISAS_LOOKUP = DISAS_TARGET_1, /* We have a variable condition exit. */
- DISAS_CHAIN = DISAS_TARGET_2, /* We have a single condition exit. */
-};
+#define DISAS_EXIT DISAS_TARGET_0 /* We want return to the cpu main loop. */
+#define DISAS_LOOKUP DISAS_TARGET_1 /* We have a variable condition exit. */
+#define DISAS_CHAIN DISAS_TARGET_2 /* We have a single condition exit. */
typedef struct DisasContext DisasContext;
/* This is the state at translation time. */
struct DisasContext {
- TranslationBlock *tb;
+ DisasContextBase base;
CPUAVRState *env;
CPUState *cs;
/* Routine used to access memory */
int memidx;
- int bstate;
- int singlestep;
/*
* some AVR instructions can make the following instruction to be skipped
* used in the following manner (sketch)
*
* TCGLabel *skip_label = NULL;
- * if (ctx.skip_cond != TCG_COND_NEVER) {
+ * if (ctx->skip_cond != TCG_COND_NEVER) {
* skip_label = gen_new_label();
* tcg_gen_brcond_tl(skip_cond, skip_var0, skip_var1, skip_label);
* }
*
- * if (free_skip_var0) {
- * tcg_temp_free(skip_var0);
- * free_skip_var0 = false;
- * }
- *
- * translate(&ctx);
+ * translate(ctx);
*
* if (skip_label) {
* gen_set_label(skip_label);
TCGv skip_var0;
TCGv skip_var1;
TCGCond skip_cond;
- bool free_skip_var0;
};
+void avr_cpu_tcg_init(void)
+{
+ int i;
+
+#define AVR_REG_OFFS(x) offsetof(CPUAVRState, x)
+ cpu_pc = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(pc_w), "pc");
+ cpu_Cf = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(sregC), "Cf");
+ cpu_Zf = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(sregZ), "Zf");
+ cpu_Nf = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(sregN), "Nf");
+ cpu_Vf = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(sregV), "Vf");
+ cpu_Sf = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(sregS), "Sf");
+ cpu_Hf = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(sregH), "Hf");
+ cpu_Tf = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(sregT), "Tf");
+ cpu_If = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(sregI), "If");
+ cpu_rampD = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(rampD), "rampD");
+ cpu_rampX = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(rampX), "rampX");
+ cpu_rampY = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(rampY), "rampY");
+ cpu_rampZ = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(rampZ), "rampZ");
+ cpu_eind = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(eind), "eind");
+ cpu_sp = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(sp), "sp");
+ cpu_skip = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(skip), "skip");
+
+ for (i = 0; i < NUMBER_OF_CPU_REGISTERS; i++) {
+ cpu_r[i] = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(r[i]),
+ reg_names[i]);
+ }
+#undef AVR_REG_OFFS
+}
+
static int to_regs_16_31_by_one(DisasContext *ctx, int indx)
{
return 16 + (indx % 16);
static bool avr_have_feature(DisasContext *ctx, int feature)
{
if (!avr_feature(ctx->env, feature)) {
- gen_helper_unsupported(cpu_env);
- ctx->bstate = DISAS_NORETURN;
+ gen_helper_unsupported(tcg_env);
+ ctx->base.is_jmp = DISAS_NORETURN;
return false;
}
return true;
}
static bool decode_insn(DisasContext *ctx, uint16_t insn);
-#include "decode_insn.inc.c"
+#include "decode-insn.c.inc"
/*
* Arithmetic Instructions
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)
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)
tcg_gen_shri_tl(cpu_Cf, t2, 7); /* Cf = t2(7) */
tcg_gen_shri_tl(cpu_Hf, t2, 3); /* Hf = t2(3) */
tcg_gen_andi_tl(cpu_Hf, cpu_Hf, 1);
-
- tcg_temp_free_i32(t3);
- tcg_temp_free_i32(t2);
- tcg_temp_free_i32(t1);
}
static void gen_sub_Vf(TCGv R, TCGv Rd, TCGv Rr)
tcg_gen_and_tl(t1, t1, t2);
tcg_gen_shri_tl(cpu_Vf, t1, 7); /* Vf = t1(7) */
-
- tcg_temp_free_i32(t2);
- tcg_temp_free_i32(t1);
}
static void gen_NSf(TCGv R)
/* update output registers */
tcg_gen_mov_tl(Rd, R);
-
- tcg_temp_free_i32(R);
-
return true;
}
/* update output registers */
tcg_gen_mov_tl(Rd, R);
-
- tcg_temp_free_i32(R);
-
return true;
}
/* update output registers */
tcg_gen_andi_tl(RdL, R, 0xff);
tcg_gen_shri_tl(RdH, R, 8);
-
- tcg_temp_free_i32(Rd);
- tcg_temp_free_i32(R);
-
return true;
}
/* update output registers */
tcg_gen_mov_tl(Rd, R);
-
- tcg_temp_free_i32(R);
-
return true;
}
static bool trans_SUBI(DisasContext *ctx, arg_SUBI *a)
{
TCGv Rd = cpu_r[a->rd];
- TCGv Rr = tcg_const_i32(a->imm);
+ TCGv Rr = tcg_constant_i32(a->imm);
TCGv R = tcg_temp_new_i32();
tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Imm */
/* update output registers */
tcg_gen_mov_tl(Rd, R);
-
- tcg_temp_free_i32(R);
- tcg_temp_free_i32(Rr);
-
return true;
}
TCGv Rd = cpu_r[a->rd];
TCGv Rr = cpu_r[a->rr];
TCGv R = tcg_temp_new_i32();
- TCGv zero = tcg_const_i32(0);
+ TCGv zero = tcg_constant_i32(0);
tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr - Cf */
tcg_gen_sub_tl(R, R, cpu_Cf);
/* update output registers */
tcg_gen_mov_tl(Rd, R);
-
- tcg_temp_free_i32(zero);
- tcg_temp_free_i32(R);
-
return true;
}
static bool trans_SBCI(DisasContext *ctx, arg_SBCI *a)
{
TCGv Rd = cpu_r[a->rd];
- TCGv Rr = tcg_const_i32(a->imm);
+ TCGv Rr = tcg_constant_i32(a->imm);
TCGv R = tcg_temp_new_i32();
- TCGv zero = tcg_const_i32(0);
+ TCGv zero = tcg_constant_i32(0);
tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr - Cf */
tcg_gen_sub_tl(R, R, cpu_Cf);
/* update output registers */
tcg_gen_mov_tl(Rd, R);
-
- tcg_temp_free_i32(zero);
- tcg_temp_free_i32(R);
- tcg_temp_free_i32(Rr);
-
return true;
}
/* update output registers */
tcg_gen_andi_tl(RdL, R, 0xff);
tcg_gen_shri_tl(RdH, R, 8);
-
- tcg_temp_free_i32(Rd);
- tcg_temp_free_i32(R);
-
return true;
}
/* update output registers */
tcg_gen_mov_tl(Rd, R);
-
- tcg_temp_free_i32(R);
-
return true;
}
/* update output registers */
tcg_gen_mov_tl(Rd, R);
-
- tcg_temp_free_i32(R);
-
return true;
}
static bool trans_COM(DisasContext *ctx, arg_COM *a)
{
TCGv Rd = cpu_r[a->rd];
- TCGv R = tcg_temp_new_i32();
tcg_gen_xori_tl(Rd, Rd, 0xff);
tcg_gen_movi_tl(cpu_Cf, 1); /* Cf = 1 */
tcg_gen_movi_tl(cpu_Vf, 0); /* Vf = 0 */
gen_ZNSf(Rd);
-
- tcg_temp_free_i32(R);
-
return true;
}
static bool trans_NEG(DisasContext *ctx, arg_NEG *a)
{
TCGv Rd = cpu_r[a->rd];
- TCGv t0 = tcg_const_i32(0);
+ TCGv t0 = tcg_constant_i32(0);
TCGv R = tcg_temp_new_i32();
tcg_gen_sub_tl(R, t0, Rd); /* R = 0 - Rd */
/* update output registers */
tcg_gen_mov_tl(Rd, R);
-
- tcg_temp_free_i32(t0);
- tcg_temp_free_i32(R);
-
return true;
}
/* update status register */
tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
-
- tcg_temp_free_i32(R);
-
return true;
}
/* update status register */
tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
-
- tcg_temp_free_i32(t1);
- tcg_temp_free_i32(t0);
- tcg_temp_free_i32(R);
-
return true;
}
/* update status register */
tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
-
- tcg_temp_free_i32(t0);
- tcg_temp_free_i32(R);
-
return true;
}
tcg_gen_andi_tl(R0, R, 0xff);
tcg_gen_shri_tl(R1, R, 8);
tcg_gen_andi_tl(R1, R1, 0xff);
-
-
- tcg_temp_free_i32(R);
-
return true;
}
tcg_gen_andi_tl(R0, R, 0xff);
tcg_gen_shri_tl(R1, R, 8);
tcg_gen_andi_tl(R1, R1, 0xff);
-
- tcg_temp_free_i32(t1);
- tcg_temp_free_i32(t0);
- tcg_temp_free_i32(R);
-
return true;
}
tcg_gen_andi_tl(R0, R, 0xff);
tcg_gen_shri_tl(R1, R, 8);
tcg_gen_andi_tl(R1, R1, 0xff);
-
- tcg_temp_free_i32(t0);
- tcg_temp_free_i32(R);
-
return true;
}
{
tcg_gen_deposit_tl(cpu_pc, cpu_r[30], cpu_r[31], 8, 8);
tcg_gen_or_tl(cpu_pc, cpu_pc, cpu_eind);
- ctx->bstate = DISAS_LOOKUP;
+ ctx->base.is_jmp = DISAS_LOOKUP;
}
static void gen_jmp_z(DisasContext *ctx)
{
tcg_gen_deposit_tl(cpu_pc, cpu_r[30], cpu_r[31], 8, 8);
- ctx->bstate = DISAS_LOOKUP;
+ ctx->base.is_jmp = DISAS_LOOKUP;
}
static void gen_push_ret(DisasContext *ctx, int ret)
{
if (avr_feature(ctx->env, AVR_FEATURE_1_BYTE_PC)) {
-
- TCGv t0 = tcg_const_i32((ret & 0x0000ff));
+ TCGv t0 = tcg_constant_i32(ret & 0x0000ff);
tcg_gen_qemu_st_tl(t0, cpu_sp, MMU_DATA_IDX, MO_UB);
tcg_gen_subi_tl(cpu_sp, cpu_sp, 1);
-
- tcg_temp_free_i32(t0);
} else if (avr_feature(ctx->env, AVR_FEATURE_2_BYTE_PC)) {
-
- TCGv t0 = tcg_const_i32((ret & 0x00ffff));
+ TCGv t0 = tcg_constant_i32(ret & 0x00ffff);
tcg_gen_subi_tl(cpu_sp, cpu_sp, 1);
tcg_gen_qemu_st_tl(t0, cpu_sp, MMU_DATA_IDX, MO_BEUW);
tcg_gen_subi_tl(cpu_sp, cpu_sp, 1);
-
- tcg_temp_free_i32(t0);
-
} else if (avr_feature(ctx->env, AVR_FEATURE_3_BYTE_PC)) {
-
- TCGv lo = tcg_const_i32((ret & 0x0000ff));
- TCGv hi = tcg_const_i32((ret & 0xffff00) >> 8);
+ TCGv lo = tcg_constant_i32(ret & 0x0000ff);
+ TCGv hi = tcg_constant_i32((ret & 0xffff00) >> 8);
tcg_gen_qemu_st_tl(lo, cpu_sp, MMU_DATA_IDX, MO_UB);
tcg_gen_subi_tl(cpu_sp, cpu_sp, 2);
tcg_gen_qemu_st_tl(hi, cpu_sp, MMU_DATA_IDX, MO_BEUW);
tcg_gen_subi_tl(cpu_sp, cpu_sp, 1);
-
- tcg_temp_free_i32(lo);
- tcg_temp_free_i32(hi);
}
}
tcg_gen_qemu_ld_tl(lo, cpu_sp, MMU_DATA_IDX, MO_UB);
tcg_gen_deposit_tl(ret, lo, hi, 8, 16);
-
- tcg_temp_free_i32(lo);
- tcg_temp_free_i32(hi);
}
}
static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
{
- TranslationBlock *tb = ctx->tb;
+ const TranslationBlock *tb = ctx->base.tb;
- if (ctx->singlestep == 0) {
+ if (translator_use_goto_tb(&ctx->base, dest)) {
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);
+ tcg_gen_lookup_and_goto_ptr();
}
- ctx->bstate = DISAS_NORETURN;
+ ctx->base.is_jmp = DISAS_NORETURN;
}
/*
{
gen_pop_ret(ctx, cpu_pc);
- ctx->bstate = DISAS_LOOKUP;
+ ctx->base.is_jmp = DISAS_LOOKUP;
return true;
}
tcg_gen_movi_tl(cpu_If, 1);
/* Need to return to main loop to re-evaluate interrupts. */
- ctx->bstate = DISAS_EXIT;
+ ctx->base.is_jmp = DISAS_EXIT;
return true;
}
gen_sub_CHf(R, Rd, Rr);
gen_sub_Vf(R, Rd, Rr);
gen_ZNSf(R);
-
- tcg_temp_free_i32(R);
-
return true;
}
TCGv Rd = cpu_r[a->rd];
TCGv Rr = cpu_r[a->rr];
TCGv R = tcg_temp_new_i32();
- TCGv zero = tcg_const_i32(0);
+ TCGv zero = tcg_constant_i32(0);
tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr - Cf */
tcg_gen_sub_tl(R, R, cpu_Cf);
* cleared otherwise.
*/
tcg_gen_movcond_tl(TCG_COND_EQ, cpu_Zf, R, zero, cpu_Zf, zero);
-
- tcg_temp_free_i32(zero);
- tcg_temp_free_i32(R);
-
return true;
}
{
TCGv Rd = cpu_r[a->rd];
int Imm = a->imm;
- TCGv Rr = tcg_const_i32(Imm);
+ TCGv Rr = tcg_constant_i32(Imm);
TCGv R = tcg_temp_new_i32();
tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr */
gen_sub_CHf(R, Rd, Rr);
gen_sub_Vf(R, Rd, Rr);
gen_ZNSf(R);
-
- tcg_temp_free_i32(R);
- tcg_temp_free_i32(Rr);
-
return true;
}
ctx->skip_cond = TCG_COND_EQ;
ctx->skip_var0 = tcg_temp_new();
- ctx->free_skip_var0 = true;
tcg_gen_andi_tl(ctx->skip_var0, Rr, 1 << a->bit);
return true;
ctx->skip_cond = TCG_COND_NE;
ctx->skip_var0 = tcg_temp_new();
- ctx->free_skip_var0 = true;
tcg_gen_andi_tl(ctx->skip_var0, Rr, 1 << a->bit);
return true;
*/
static bool trans_SBIC(DisasContext *ctx, arg_SBIC *a)
{
- TCGv temp = tcg_const_i32(a->reg);
+ TCGv data = tcg_temp_new_i32();
+ TCGv port = tcg_constant_i32(a->reg);
- gen_helper_inb(temp, cpu_env, temp);
- tcg_gen_andi_tl(temp, temp, 1 << a->bit);
+ gen_helper_inb(data, tcg_env, port);
+ tcg_gen_andi_tl(data, data, 1 << a->bit);
ctx->skip_cond = TCG_COND_EQ;
- ctx->skip_var0 = temp;
- ctx->free_skip_var0 = true;
+ ctx->skip_var0 = data;
return true;
}
*/
static bool trans_SBIS(DisasContext *ctx, arg_SBIS *a)
{
- TCGv temp = tcg_const_i32(a->reg);
+ TCGv data = tcg_temp_new_i32();
+ TCGv port = tcg_constant_i32(a->reg);
- gen_helper_inb(temp, cpu_env, temp);
- tcg_gen_andi_tl(temp, temp, 1 << a->bit);
+ gen_helper_inb(data, tcg_env, port);
+ tcg_gen_andi_tl(data, data, 1 << a->bit);
ctx->skip_cond = TCG_COND_NE;
- ctx->skip_var0 = temp;
- ctx->free_skip_var0 = true;
+ ctx->skip_var0 = data;
return true;
}
gen_goto_tb(ctx, 0, ctx->npc + a->imm);
gen_set_label(not_taken);
- ctx->bstate = DISAS_CHAIN;
+ ctx->base.is_jmp = DISAS_CHAIN;
return true;
}
gen_goto_tb(ctx, 0, ctx->npc + a->imm);
gen_set_label(not_taken);
- ctx->bstate = DISAS_CHAIN;
+ ctx->base.is_jmp = DISAS_CHAIN;
return true;
}
*/
static void gen_data_store(DisasContext *ctx, TCGv data, TCGv addr)
{
- if (ctx->tb->flags & TB_FLAGS_FULL_ACCESS) {
- gen_helper_fullwr(cpu_env, data, addr);
+ if (ctx->base.tb->flags & TB_FLAGS_FULL_ACCESS) {
+ gen_helper_fullwr(tcg_env, data, addr);
} else {
- tcg_gen_qemu_st8(data, addr, MMU_DATA_IDX); /* mem[addr] = data */
+ tcg_gen_qemu_st_tl(data, addr, MMU_DATA_IDX, MO_UB);
}
}
static void gen_data_load(DisasContext *ctx, TCGv data, TCGv addr)
{
- if (ctx->tb->flags & TB_FLAGS_FULL_ACCESS) {
- gen_helper_fullrd(data, cpu_env, addr);
+ if (ctx->base.tb->flags & TB_FLAGS_FULL_ACCESS) {
+ gen_helper_fullrd(data, tcg_env, addr);
} else {
- tcg_gen_qemu_ld8u(data, addr, MMU_DATA_IDX); /* data = mem[addr] */
+ tcg_gen_qemu_ld_tl(data, addr, MMU_DATA_IDX, MO_UB);
}
}
tcg_gen_ori_tl(addr, addr, a->imm);
gen_data_load(ctx, Rd, addr);
-
- tcg_temp_free_i32(addr);
-
return true;
}
TCGv addr = gen_get_xaddr();
gen_data_load(ctx, Rd, addr);
-
- tcg_temp_free_i32(addr);
-
return true;
}
tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
gen_set_xaddr(addr);
-
- tcg_temp_free_i32(addr);
-
return true;
}
tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */
gen_data_load(ctx, Rd, addr);
gen_set_xaddr(addr);
-
- tcg_temp_free_i32(addr);
-
return true;
}
tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
gen_set_yaddr(addr);
-
- tcg_temp_free_i32(addr);
-
return true;
}
tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */
gen_data_load(ctx, Rd, addr);
gen_set_yaddr(addr);
-
- tcg_temp_free_i32(addr);
-
return true;
}
tcg_gen_addi_tl(addr, addr, a->imm); /* addr = addr + q */
gen_data_load(ctx, Rd, addr);
-
- tcg_temp_free_i32(addr);
-
return true;
}
tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
gen_set_zaddr(addr);
-
- tcg_temp_free_i32(addr);
-
return true;
}
gen_data_load(ctx, Rd, addr);
gen_set_zaddr(addr);
-
- tcg_temp_free_i32(addr);
-
return true;
}
tcg_gen_addi_tl(addr, addr, a->imm); /* addr = addr + q */
gen_data_load(ctx, Rd, addr);
-
- tcg_temp_free_i32(addr);
-
return true;
}
tcg_gen_shli_tl(addr, addr, 16);
tcg_gen_ori_tl(addr, addr, a->imm);
gen_data_store(ctx, Rd, addr);
-
- tcg_temp_free_i32(addr);
-
return true;
}
TCGv addr = gen_get_xaddr();
gen_data_store(ctx, Rd, addr);
-
- tcg_temp_free_i32(addr);
-
return true;
}
gen_data_store(ctx, Rd, addr);
tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
gen_set_xaddr(addr);
-
- tcg_temp_free_i32(addr);
-
return true;
}
tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */
gen_data_store(ctx, Rd, addr);
gen_set_xaddr(addr);
-
- tcg_temp_free_i32(addr);
-
return true;
}
gen_data_store(ctx, Rd, addr);
tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
gen_set_yaddr(addr);
-
- tcg_temp_free_i32(addr);
-
return true;
}
tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */
gen_data_store(ctx, Rd, addr);
gen_set_yaddr(addr);
-
- tcg_temp_free_i32(addr);
-
return true;
}
tcg_gen_addi_tl(addr, addr, a->imm); /* addr = addr + q */
gen_data_store(ctx, Rd, addr);
-
- tcg_temp_free_i32(addr);
-
return true;
}
tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
gen_set_zaddr(addr);
-
- tcg_temp_free_i32(addr);
-
return true;
}
gen_data_store(ctx, Rd, addr);
gen_set_zaddr(addr);
-
- tcg_temp_free_i32(addr);
-
return true;
}
tcg_gen_addi_tl(addr, addr, a->imm); /* addr = addr + q */
gen_data_store(ctx, Rd, addr);
-
- tcg_temp_free_i32(addr);
-
return true;
}
tcg_gen_shli_tl(addr, H, 8); /* addr = H:L */
tcg_gen_or_tl(addr, addr, L);
- tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */
-
- tcg_temp_free_i32(addr);
-
+ tcg_gen_qemu_ld_tl(Rd, addr, MMU_CODE_IDX, MO_UB);
return true;
}
tcg_gen_shli_tl(addr, H, 8); /* addr = H:L */
tcg_gen_or_tl(addr, addr, L);
- tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */
-
- tcg_temp_free_i32(addr);
-
+ tcg_gen_qemu_ld_tl(Rd, addr, MMU_CODE_IDX, MO_UB);
return true;
}
tcg_gen_shli_tl(addr, H, 8); /* addr = H:L */
tcg_gen_or_tl(addr, addr, L);
- tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */
+ tcg_gen_qemu_ld_tl(Rd, addr, MMU_CODE_IDX, MO_UB);
tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
tcg_gen_andi_tl(L, addr, 0xff);
tcg_gen_shri_tl(addr, addr, 8);
tcg_gen_andi_tl(H, addr, 0xff);
-
- tcg_temp_free_i32(addr);
-
return true;
}
TCGv Rd = cpu_r[0];
TCGv addr = gen_get_zaddr();
- tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */
-
- tcg_temp_free_i32(addr);
-
+ tcg_gen_qemu_ld_tl(Rd, addr, MMU_CODE_IDX, MO_UB);
return true;
}
TCGv Rd = cpu_r[a->rd];
TCGv addr = gen_get_zaddr();
- tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */
-
- tcg_temp_free_i32(addr);
-
+ tcg_gen_qemu_ld_tl(Rd, addr, MMU_CODE_IDX, MO_UB);
return true;
}
TCGv Rd = cpu_r[a->rd];
TCGv addr = gen_get_zaddr();
- tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */
+ tcg_gen_qemu_ld_tl(Rd, addr, MMU_CODE_IDX, MO_UB);
tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
gen_set_zaddr(addr);
-
- tcg_temp_free_i32(addr);
-
return true;
}
static bool trans_IN(DisasContext *ctx, arg_IN *a)
{
TCGv Rd = cpu_r[a->rd];
- TCGv port = tcg_const_i32(a->imm);
-
- gen_helper_inb(Rd, cpu_env, port);
-
- tcg_temp_free_i32(port);
+ TCGv port = tcg_constant_i32(a->imm);
+ gen_helper_inb(Rd, tcg_env, port);
return true;
}
static bool trans_OUT(DisasContext *ctx, arg_OUT *a)
{
TCGv Rd = cpu_r[a->rd];
- TCGv port = tcg_const_i32(a->imm);
-
- gen_helper_outb(cpu_env, port, Rd);
-
- tcg_temp_free_i32(port);
+ TCGv port = tcg_constant_i32(a->imm);
+ gen_helper_outb(tcg_env, port, Rd);
return true;
}
gen_data_load(ctx, t0, addr);
gen_data_store(ctx, Rd, addr);
tcg_gen_mov_tl(Rd, t0);
-
- tcg_temp_free_i32(t0);
- tcg_temp_free_i32(addr);
-
return true;
}
tcg_gen_or_tl(t1, t0, Rr);
tcg_gen_mov_tl(Rr, t0); /* Rr = t0 */
gen_data_store(ctx, t1, addr); /* mem[addr] = t1 */
-
- tcg_temp_free_i32(t1);
- tcg_temp_free_i32(t0);
- tcg_temp_free_i32(addr);
-
return true;
}
tcg_gen_andc_tl(t1, t0, Rr); /* t1 = t0 & (0xff - Rr) = t0 & ~Rr */
tcg_gen_mov_tl(Rr, t0); /* Rr = t0 */
gen_data_store(ctx, t1, addr); /* mem[addr] = t1 */
-
- tcg_temp_free_i32(t1);
- tcg_temp_free_i32(t0);
- tcg_temp_free_i32(addr);
-
return true;
}
tcg_gen_xor_tl(t1, t0, Rd);
tcg_gen_mov_tl(Rd, t0); /* Rd = t0 */
gen_data_store(ctx, t1, addr); /* mem[addr] = t1 */
-
- tcg_temp_free_i32(t1);
- tcg_temp_free_i32(t0);
- tcg_temp_free_i32(addr);
-
return true;
}
/* update status register */
gen_rshift_ZNVSf(Rd);
-
- tcg_temp_free_i32(t0);
-
return true;
}
/* update status register */
gen_rshift_ZNVSf(Rd);
-
- tcg_temp_free_i32(t0);
-
return true;
}
tcg_gen_andi_tl(t1, Rd, 0xf0);
tcg_gen_shri_tl(t1, t1, 4);
tcg_gen_or_tl(Rd, t0, t1);
-
- tcg_temp_free_i32(t1);
- tcg_temp_free_i32(t0);
-
return true;
}
static bool trans_SBI(DisasContext *ctx, arg_SBI *a)
{
TCGv data = tcg_temp_new_i32();
- TCGv port = tcg_const_i32(a->reg);
+ TCGv port = tcg_constant_i32(a->reg);
- gen_helper_inb(data, cpu_env, port);
+ gen_helper_inb(data, tcg_env, port);
tcg_gen_ori_tl(data, data, 1 << a->bit);
- gen_helper_outb(cpu_env, port, data);
-
- tcg_temp_free_i32(port);
- tcg_temp_free_i32(data);
-
+ gen_helper_outb(tcg_env, port, data);
return true;
}
static bool trans_CBI(DisasContext *ctx, arg_CBI *a)
{
TCGv data = tcg_temp_new_i32();
- TCGv port = tcg_const_i32(a->reg);
+ TCGv port = tcg_constant_i32(a->reg);
- gen_helper_inb(data, cpu_env, port);
+ gen_helper_inb(data, tcg_env, port);
tcg_gen_andi_tl(data, data, ~(1 << a->bit));
- gen_helper_outb(cpu_env, port, data);
-
- tcg_temp_free_i32(data);
- tcg_temp_free_i32(port);
-
+ gen_helper_outb(tcg_env, port, data);
return true;
}
tcg_gen_andi_tl(Rd, Rd, ~(1u << a->bit)); /* clear bit */
tcg_gen_shli_tl(t1, cpu_Tf, a->bit); /* create mask */
tcg_gen_or_tl(Rd, Rd, t1);
-
- tcg_temp_free_i32(t1);
-
return true;
}
#ifdef BREAKPOINT_ON_BREAK
tcg_gen_movi_tl(cpu_pc, ctx->npc - 1);
- gen_helper_debug(cpu_env);
- ctx->bstate = DISAS_EXIT;
+ gen_helper_debug(tcg_env);
+ ctx->base.is_jmp = DISAS_EXIT;
#else
/* NOP */
#endif
*/
static bool trans_SLEEP(DisasContext *ctx, arg_SLEEP *a)
{
- gen_helper_sleep(cpu_env);
- ctx->bstate = DISAS_NORETURN;
+ gen_helper_sleep(tcg_env);
+ ctx->base.is_jmp = DISAS_NORETURN;
return true;
}
*/
static bool trans_WDR(DisasContext *ctx, arg_WDR *a)
{
- gen_helper_wdr(cpu_env);
+ gen_helper_wdr(tcg_env);
return true;
}
uint32_t opcode = next_word(ctx);
if (!decode_insn(ctx, opcode)) {
- gen_helper_unsupported(cpu_env);
- ctx->bstate = DISAS_NORETURN;
+ gen_helper_unsupported(tcg_env);
+ ctx->base.is_jmp = DISAS_NORETURN;
}
}
ctx->skip_cond = TCG_COND_NE;
break;
}
- if (ctx->free_skip_var0) {
- tcg_temp_free(ctx->skip_var0);
- ctx->free_skip_var0 = false;
- }
ctx->skip_var0 = cpu_skip;
return true;
}
-void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns)
+static void avr_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
{
- CPUAVRState *env = cs->env_ptr;
- DisasContext ctx = {
- .tb = tb,
- .cs = cs,
- .env = env,
- .memidx = 0,
- .bstate = DISAS_NEXT,
- .skip_cond = TCG_COND_NEVER,
- .singlestep = cs->singlestep_enabled,
- };
- target_ulong pc_start = tb->pc / 2;
- int num_insns = 0;
+ DisasContext *ctx = container_of(dcbase, DisasContext, base);
+ CPUAVRState *env = cpu_env(cs);
+ uint32_t tb_flags = ctx->base.tb->flags;
+
+ ctx->cs = cs;
+ ctx->env = env;
+ ctx->npc = ctx->base.pc_first / 2;
- if (tb->flags & TB_FLAGS_FULL_ACCESS) {
+ ctx->skip_cond = TCG_COND_NEVER;
+ if (tb_flags & TB_FLAGS_SKIP) {
+ ctx->skip_cond = TCG_COND_ALWAYS;
+ ctx->skip_var0 = cpu_skip;
+ }
+
+ if (tb_flags & TB_FLAGS_FULL_ACCESS) {
/*
* This flag is set by ST/LD instruction we will regenerate it ONLY
* with mem/cpu memory access instead of mem access
*/
- max_insns = 1;
- }
- if (ctx.singlestep) {
- max_insns = 1;
+ ctx->base.max_insns = 1;
}
+}
- gen_tb_start(tb);
+static void avr_tr_tb_start(DisasContextBase *db, CPUState *cs)
+{
+}
- ctx.npc = pc_start;
- if (tb->flags & TB_FLAGS_SKIP) {
- ctx.skip_cond = TCG_COND_ALWAYS;
- ctx.skip_var0 = cpu_skip;
- }
+static void avr_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
+{
+ DisasContext *ctx = container_of(dcbase, DisasContext, base);
- do {
- TCGLabel *skip_label = NULL;
+ tcg_gen_insn_start(ctx->npc);
+}
- /* translate current instruction */
- tcg_gen_insn_start(ctx.npc);
- num_insns++;
+static void avr_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
+{
+ DisasContext *ctx = container_of(dcbase, DisasContext, base);
+ TCGLabel *skip_label = NULL;
- /*
- * this is due to some strange GDB behavior
- * let's assume main has address 0x100
- * b main - sets breakpoint at address 0x00000100 (code)
- * b *0x100 - sets breakpoint at address 0x00800100 (data)
- */
- if (unlikely(!ctx.singlestep &&
- (cpu_breakpoint_test(cs, OFFSET_CODE + ctx.npc * 2, BP_ANY) ||
- cpu_breakpoint_test(cs, OFFSET_DATA + ctx.npc * 2, BP_ANY)))) {
- canonicalize_skip(&ctx);
- tcg_gen_movi_tl(cpu_pc, ctx.npc);
- gen_helper_debug(cpu_env);
- goto done_generating;
+ /* Conditionally skip the next instruction, if indicated. */
+ if (ctx->skip_cond != TCG_COND_NEVER) {
+ skip_label = gen_new_label();
+ if (ctx->skip_var0 == cpu_skip) {
+ /*
+ * Copy cpu_skip so that we may zero it before the branch.
+ * This ensures that cpu_skip is non-zero after the label
+ * if and only if the skipped insn itself sets a skip.
+ */
+ ctx->skip_var0 = tcg_temp_new();
+ tcg_gen_mov_tl(ctx->skip_var0, cpu_skip);
+ tcg_gen_movi_tl(cpu_skip, 0);
}
-
- /* Conditionally skip the next instruction, if indicated. */
- if (ctx.skip_cond != TCG_COND_NEVER) {
- skip_label = gen_new_label();
- if (ctx.skip_var0 == cpu_skip) {
- /*
- * Copy cpu_skip so that we may zero it before the branch.
- * This ensures that cpu_skip is non-zero after the label
- * if and only if the skipped insn itself sets a skip.
- */
- ctx.free_skip_var0 = true;
- ctx.skip_var0 = tcg_temp_new();
- tcg_gen_mov_tl(ctx.skip_var0, cpu_skip);
- tcg_gen_movi_tl(cpu_skip, 0);
- }
- if (ctx.skip_var1 == NULL) {
- tcg_gen_brcondi_tl(ctx.skip_cond, ctx.skip_var0, 0, skip_label);
- } else {
- tcg_gen_brcond_tl(ctx.skip_cond, ctx.skip_var0,
- ctx.skip_var1, skip_label);
- ctx.skip_var1 = NULL;
- }
- if (ctx.free_skip_var0) {
- tcg_temp_free(ctx.skip_var0);
- ctx.free_skip_var0 = false;
- }
- ctx.skip_cond = TCG_COND_NEVER;
- ctx.skip_var0 = NULL;
+ if (ctx->skip_var1 == NULL) {
+ tcg_gen_brcondi_tl(ctx->skip_cond, ctx->skip_var0, 0, skip_label);
+ } else {
+ tcg_gen_brcond_tl(ctx->skip_cond, ctx->skip_var0,
+ ctx->skip_var1, skip_label);
+ ctx->skip_var1 = NULL;
}
+ ctx->skip_cond = TCG_COND_NEVER;
+ ctx->skip_var0 = NULL;
+ }
- translate(&ctx);
+ translate(ctx);
- if (skip_label) {
- canonicalize_skip(&ctx);
- gen_set_label(skip_label);
- if (ctx.bstate == DISAS_NORETURN) {
- ctx.bstate = DISAS_CHAIN;
+ ctx->base.pc_next = ctx->npc * 2;
+
+ if (skip_label) {
+ canonicalize_skip(ctx);
+ gen_set_label(skip_label);
+
+ switch (ctx->base.is_jmp) {
+ case DISAS_NORETURN:
+ ctx->base.is_jmp = DISAS_CHAIN;
+ break;
+ case DISAS_NEXT:
+ if (ctx->base.tb->flags & TB_FLAGS_SKIP) {
+ ctx->base.is_jmp = DISAS_TOO_MANY;
}
+ break;
+ default:
+ break;
}
- } while (ctx.bstate == DISAS_NEXT
- && num_insns < max_insns
- && (ctx.npc - pc_start) * 2 < TARGET_PAGE_SIZE - 4
- && !tcg_op_buf_full());
+ }
- if (tb->cflags & CF_LAST_IO) {
- gen_io_end();
+ if (ctx->base.is_jmp == DISAS_NEXT) {
+ target_ulong page_first = ctx->base.pc_first & TARGET_PAGE_MASK;
+
+ if ((ctx->base.pc_next - page_first) >= TARGET_PAGE_SIZE - 4) {
+ ctx->base.is_jmp = DISAS_TOO_MANY;
+ }
}
+}
- bool nonconst_skip = canonicalize_skip(&ctx);
+static void avr_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
+{
+ DisasContext *ctx = container_of(dcbase, DisasContext, base);
+ bool nonconst_skip = canonicalize_skip(ctx);
+ /*
+ * Because we disable interrupts while env->skip is set,
+ * we must return to the main loop to re-evaluate afterward.
+ */
+ bool force_exit = ctx->base.tb->flags & TB_FLAGS_SKIP;
- switch (ctx.bstate) {
+ switch (ctx->base.is_jmp) {
case DISAS_NORETURN:
assert(!nonconst_skip);
break;
case DISAS_NEXT:
case DISAS_TOO_MANY:
case DISAS_CHAIN:
- if (!nonconst_skip) {
+ if (!nonconst_skip && !force_exit) {
/* Note gen_goto_tb checks singlestep. */
- gen_goto_tb(&ctx, 1, ctx.npc);
+ gen_goto_tb(ctx, 1, ctx->npc);
break;
}
- tcg_gen_movi_tl(cpu_pc, ctx.npc);
+ tcg_gen_movi_tl(cpu_pc, ctx->npc);
/* fall through */
case DISAS_LOOKUP:
- if (!ctx.singlestep) {
+ if (!force_exit) {
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);
- }
+ tcg_gen_exit_tb(NULL, 0);
break;
default:
g_assert_not_reached();
}
+}
-done_generating:
- gen_tb_end(tb, num_insns);
-
- tb->size = (ctx.npc - pc_start) * 2;
- tb->icount = num_insns;
+static void avr_tr_disas_log(const DisasContextBase *dcbase,
+ CPUState *cs, FILE *logfile)
+{
+ fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first));
+ target_disas(logfile, cs, dcbase->pc_first, dcbase->tb->size);
}
-void restore_state_to_opc(CPUAVRState *env, TranslationBlock *tb,
- target_ulong *data)
+static const TranslatorOps avr_tr_ops = {
+ .init_disas_context = avr_tr_init_disas_context,
+ .tb_start = avr_tr_tb_start,
+ .insn_start = avr_tr_insn_start,
+ .translate_insn = avr_tr_translate_insn,
+ .tb_stop = avr_tr_tb_stop,
+ .disas_log = avr_tr_disas_log,
+};
+
+void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
+ vaddr pc, void *host_pc)
{
- env->pc_w = data[0];
+ DisasContext dc = { };
+ translator_loop(cs, tb, max_insns, pc, host_pc, &avr_tr_ops, &dc.base);
}