/* generate intermediate code for basic block 'tb'. */ static void gen_intermediate_code_internal( Nios2CPU *cpu, TranslationBlock *tb, int search_pc) { CPUState *cs = CPU(cpu); CPUNios2State *env = &cpu->env; DisasContext dc1, *dc = &dc1; int num_insns; int max_insns; uint32_t next_page_start; int j, lj = -1; uint16_t *gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE; /* Initialize DC */ dc->cpu_env = cpu_env; dc->cpu_R = cpu_R; dc->is_jmp = DISAS_NEXT; dc->pc = tb->pc; dc->tb = tb; dc->mem_idx = cpu_mmu_index(env); /* Dump the CPU state to the log */ if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) { qemu_log("--------------\n"); log_cpu_state(CPU(env), 0); } /* Set up instruction counts */ num_insns = 0; max_insns = tb->cflags & CF_COUNT_MASK; if (max_insns == 0) { max_insns = CF_COUNT_MASK; } next_page_start = (tb->pc & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; gen_tb_start(); do { /* Mark instruction start with associated PC */ if (search_pc) { j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; if (lj < j) { lj++; while (lj < j) { tcg_ctx.gen_opc_instr_start[lj++] = 0; } } tcg_ctx.gen_opc_pc[lj] = dc->pc; tcg_ctx.gen_opc_instr_start[lj] = 1; tcg_ctx.gen_opc_icount[lj] = num_insns; } LOG_DIS("%8.8x:\t", dc->pc); if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) { gen_io_start(); } /* Decode an instruction */ handle_instruction(dc, env); dc->pc += 4; num_insns++; /* Translation stops when a conditional branch is encountered. * Otherwise the subsequent code could get translated several times. * Also stop translation when a page boundary is reached. This * ensures prefetch aborts occur at the right place. */ } while (!dc->is_jmp && tcg_ctx.gen_opc_ptr < gen_opc_end && !cs->singlestep_enabled && !singlestep && dc->pc < next_page_start && num_insns < max_insns); if (tb->cflags & CF_LAST_IO) { gen_io_end(); } /* Indicate where the next block should start */ switch (dc->is_jmp) { case DISAS_NEXT: /* Save the current PC back into the CPU register */ tcg_gen_movi_tl(cpu_R[R_PC], dc->pc); tcg_gen_exit_tb(0); break; default: case DISAS_JUMP: case DISAS_UPDATE: /* The jump will already have updated the PC register */ tcg_gen_exit_tb(0); break; case DISAS_TB_JUMP: /* nothing more to generate */ break; } /* End off the block */ gen_tb_end(tb, num_insns); *tcg_ctx.gen_opc_ptr = INDEX_op_end; /* Mark instruction starts for the final generated instruction */ if (search_pc) { j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; lj++; while (lj <= j) { tcg_ctx.gen_opc_instr_start[lj++] = 0; } } else { tb->size = dc->pc - tb->pc; tb->icount = num_insns; } #ifdef DEBUG_DISAS if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) { qemu_log("----------------\n"); qemu_log("IN: %s\n", lookup_symbol(tb->pc)); log_target_disas(env, tb->pc, dc->pc - tb->pc, 0); qemu_log("\nisize=%d osize=%td\n", dc->pc - tb->pc, tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf); } #endif }
/* 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 }