static inline void gen_cond_branch(DisasContext *dc, int cond) { TCGLabel *l1 = gen_new_label(); tcg_gen_brcond_tl(cond, cpu_R[dc->r0], cpu_R[dc->r1], l1); gen_goto_tb(dc, 0, dc->pc + 4); gen_set_label(l1); gen_goto_tb(dc, 1, dc->pc + (sign_extend(dc->imm16 << 2, 16))); dc->is_jmp = DISAS_TB_JUMP; }
/* Immediate conditional jump (bt or bf) */ static void gen_conditional_jump(DisasContext * ctx, target_ulong ift, target_ulong ifnott) { int l1; l1 = gen_new_label(); gen_op_jT(l1); gen_goto_tb(ctx, 0, ifnott); gen_set_label(l1); gen_goto_tb(ctx, 1, ift); }
static void dec_bi(DisasContext *dc) { LOG_DIS("bi %d\n", sign_extend(dc->imm26 << 2, 26)); gen_goto_tb(dc, 0, dc->pc + (sign_extend(dc->imm26 << 2, 26))); dc->is_jmp = DISAS_TB_JUMP; }
static void dec_calli(DisasContext *dc) { LOG_DIS("calli %d\n", sign_extend(dc->imm26, 26) * 4); tcg_gen_movi_tl(cpu_R[R_RA], dc->pc + 4); gen_goto_tb(dc, 0, dc->pc + (sign_extend(dc->imm26 << 2, 26))); dc->is_jmp = DISAS_TB_JUMP; }
/* Delayed conditional jump (bt or bf) */ static void gen_delayed_conditional_jump(DisasContext * ctx) { int l1; l1 = gen_new_label(); gen_op_jdelayed(l1); gen_goto_tb(ctx, 1, ctx->pc); gen_set_label(l1); gen_jump(ctx); }
static void gen_jump(DisasContext * ctx) { if (ctx->delayed_pc == (uint32_t) - 1) { /* Target is not statically known, it comes necessarily from a delayed jump as immediate jump are conditinal jumps */ gen_op_movl_delayed_pc_PC(); gen_op_movl_imm_T0(0); if (ctx->singlestep_enabled) gen_op_debug(); gen_op_exit_tb(); } else { gen_goto_tb(ctx, 0, ctx->delayed_pc); } }
/* generate intermediate code for basic block 'tb'. */ void gen_intermediate_code(CPULM32State *env, struct TranslationBlock *tb) { LM32CPU *cpu = lm32_env_get_cpu(env); CPUState *cs = CPU(cpu); struct DisasContext ctx, *dc = &ctx; uint32_t pc_start; uint32_t next_page_start; int num_insns; int max_insns; pc_start = tb->pc; dc->features = cpu->features; dc->num_breakpoints = cpu->num_breakpoints; dc->num_watchpoints = cpu->num_watchpoints; dc->tb = tb; dc->is_jmp = DISAS_NEXT; dc->pc = pc_start; dc->singlestep_enabled = cs->singlestep_enabled; if (pc_start & 3) { qemu_log_mask(LOG_GUEST_ERROR, "unaligned PC=%x. Ignoring lowest bits.\n", pc_start); pc_start &= ~3; } next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; 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); do { tcg_gen_insn_start(dc->pc); num_insns++; if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) { tcg_gen_movi_tl(cpu_pc, dc->pc); t_gen_raise_exception(dc, EXCP_DEBUG); dc->is_jmp = DISAS_UPDATE; /* 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. */ dc->pc += 4; break; } /* Pretty disas. */ LOG_DIS("%8.8x:\t", dc->pc); if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) { gen_io_start(); } decode(dc, cpu_ldl_code(env, dc->pc)); dc->pc += 4; } while (!dc->is_jmp && !tcg_op_buf_full() && !cs->singlestep_enabled && !singlestep && (dc->pc < next_page_start) && num_insns < max_insns); if (tb->cflags & CF_LAST_IO) { gen_io_end(); } if (unlikely(cs->singlestep_enabled)) { if (dc->is_jmp == DISAS_NEXT) { tcg_gen_movi_tl(cpu_pc, dc->pc); } t_gen_raise_exception(dc, EXCP_DEBUG); } else { switch (dc->is_jmp) { case DISAS_NEXT: gen_goto_tb(dc, 1, dc->pc); break; default: case DISAS_JUMP: case DISAS_UPDATE: /* indicate that the hash table must be used to find the next TB */ tcg_gen_exit_tb(0); break; case DISAS_TB_JUMP: /* nothing more to generate */ break; } } gen_tb_end(tb, num_insns); tb->size = dc->pc - pc_start; tb->icount = num_insns; #ifdef DEBUG_DISAS if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) { qemu_log("\n"); log_target_disas(cs, pc_start, dc->pc - pc_start, 0); qemu_log("\nisize=%d osize=%d\n", dc->pc - pc_start, tcg_op_buf_count()); } #endif }