gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, int search_pc) { uint16_t *gen_opc_end; uint32_t pc_start; int j, lj; struct DisasContext ctx; struct DisasContext *dc = &ctx; uint32_t next_page_start, org_flags; target_ulong npc; int num_insns; int max_insns; qemu_log_try_set_file(stderr); pc_start = tb->pc; dc->env = env; dc->tb = tb; org_flags = dc->synced_flags = dc->tb_flags = tb->flags; gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; dc->is_jmp = DISAS_NEXT; dc->jmp = 0; dc->delayed_branch = !!(dc->tb_flags & D_FLAG); dc->pc = pc_start; dc->singlestep_enabled = env->singlestep_enabled; dc->cpustate_changed = 0; dc->abort_at_next_insn = 0; dc->nr_nops = 0; if (pc_start & 3) cpu_abort(env, "Microblaze: unaligned PC=%x\n", pc_start); if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) { #if !SIM_COMPAT qemu_log("--------------\n"); log_cpu_state(env, 0); #endif } next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; lj = -1; num_insns = 0; max_insns = tb->cflags & CF_COUNT_MASK; if (max_insns == 0) max_insns = CF_COUNT_MASK; gen_icount_start(); do { #if SIM_COMPAT if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) { tcg_gen_movi_tl(cpu_SR[SR_PC], dc->pc); gen_helper_debug(); } #endif check_breakpoint(env, dc); if (search_pc) { j = gen_opc_ptr - gen_opc_buf; if (lj < j) { lj++; while (lj < j) gen_opc_instr_start[lj++] = 0; } gen_opc_pc[lj] = dc->pc; gen_opc_instr_start[lj] = 1; gen_opc_icount[lj] = num_insns; } /* Pretty disas. */ LOG_DIS("%8.8x:\t", dc->pc); if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) gen_io_start(); dc->clear_imm = 1; decode(dc); if (dc->clear_imm) dc->tb_flags &= ~IMM_FLAG; dc->pc += 4; num_insns++; if (dc->delayed_branch) { dc->delayed_branch--; if (!dc->delayed_branch) { if (dc->tb_flags & DRTI_FLAG) do_rti(dc); if (dc->tb_flags & DRTB_FLAG) do_rtb(dc); if (dc->tb_flags & DRTE_FLAG) do_rte(dc); /* Clear the delay slot flag. */ dc->tb_flags &= ~D_FLAG; /* If it is a direct jump, try direct chaining. */ if (dc->jmp != JMP_DIRECT) { eval_cond_jmp(dc, env_btarget, tcg_const_tl(dc->pc)); dc->is_jmp = DISAS_JUMP; } break; } } if (env->singlestep_enabled) break; } while (!dc->is_jmp && !dc->cpustate_changed && gen_opc_ptr < gen_opc_end && !singlestep && (dc->pc < next_page_start) && num_insns < max_insns); npc = dc->pc; if (dc->jmp == JMP_DIRECT) { if (dc->tb_flags & D_FLAG) { dc->is_jmp = DISAS_UPDATE; tcg_gen_movi_tl(cpu_SR[SR_PC], npc); sync_jmpstate(dc); } else npc = dc->jmp_pc; } if (tb->cflags & CF_LAST_IO) gen_io_end(); /* Force an update if the per-tb cpu state has changed. */ if (dc->is_jmp == DISAS_NEXT && (dc->cpustate_changed || org_flags != dc->tb_flags)) { dc->is_jmp = DISAS_UPDATE; tcg_gen_movi_tl(cpu_SR[SR_PC], npc); } t_sync_flags(dc); if (unlikely(env->singlestep_enabled)) { t_gen_raise_exception(dc, EXCP_DEBUG); if (dc->is_jmp == DISAS_NEXT) tcg_gen_movi_tl(cpu_SR[SR_PC], npc); } else { switch(dc->is_jmp) { case DISAS_NEXT: gen_goto_tb(dc, 1, npc); 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_icount_end(tb, num_insns); *gen_opc_ptr = INDEX_op_end; if (search_pc) { j = gen_opc_ptr - gen_opc_buf; lj++; while (lj <= j) gen_opc_instr_start[lj++] = 0; } else { tb->size = dc->pc - pc_start; tb->icount = num_insns; } #ifdef DEBUG_DISAS #if !SIM_COMPAT if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) { qemu_log("\n"); #if DISAS_GNU log_target_disas(pc_start, dc->pc - pc_start, 0); #endif qemu_log("\nisize=%d osize=%td\n", dc->pc - pc_start, gen_opc_ptr - gen_opc_buf); } #endif #endif assert(!dc->abort_at_next_insn); }