 b542683d77
			
		
	
	
		b542683d77
		
	
	
	
	
		
			
			While at it, use int for both num_insns and max_insns to make sure we have same-type comparisons. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> Reviewed-by: Michael Clark <mjc@sifive.com> Signed-off-by: Emilio G. Cota <cota@braap.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
		
			
				
	
	
		
			138 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			138 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * Generic intermediate code generation.
 | |
|  *
 | |
|  * Copyright (C) 2016-2017 Lluís Vilanova <vilanova@ac.upc.edu>
 | |
|  *
 | |
|  * This work is licensed under the terms of the GNU GPL, version 2 or later.
 | |
|  * See the COPYING file in the top-level directory.
 | |
|  */
 | |
| 
 | |
| #include "qemu/osdep.h"
 | |
| #include "qemu-common.h"
 | |
| #include "qemu/error-report.h"
 | |
| #include "cpu.h"
 | |
| #include "tcg/tcg.h"
 | |
| #include "tcg/tcg-op.h"
 | |
| #include "exec/exec-all.h"
 | |
| #include "exec/gen-icount.h"
 | |
| #include "exec/log.h"
 | |
| #include "exec/translator.h"
 | |
| 
 | |
| /* Pairs with tcg_clear_temp_count.
 | |
|    To be called by #TranslatorOps.{translate_insn,tb_stop} if
 | |
|    (1) the target is sufficiently clean to support reporting,
 | |
|    (2) as and when all temporaries are known to be consumed.
 | |
|    For most targets, (2) is at the end of translate_insn.  */
 | |
| void translator_loop_temp_check(DisasContextBase *db)
 | |
| {
 | |
|     if (tcg_check_temp_count()) {
 | |
|         qemu_log("warning: TCG temporary leaks before "
 | |
|                  TARGET_FMT_lx "\n", db->pc_next);
 | |
|     }
 | |
| }
 | |
| 
 | |
| void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
 | |
|                      CPUState *cpu, TranslationBlock *tb)
 | |
| {
 | |
|     /* Initialize DisasContext */
 | |
|     db->tb = tb;
 | |
|     db->pc_first = tb->pc;
 | |
|     db->pc_next = db->pc_first;
 | |
|     db->is_jmp = DISAS_NEXT;
 | |
|     db->num_insns = 0;
 | |
|     db->singlestep_enabled = cpu->singlestep_enabled;
 | |
| 
 | |
|     /* Instruction counting */
 | |
|     db->max_insns = tb_cflags(db->tb) & CF_COUNT_MASK;
 | |
|     if (db->max_insns == 0) {
 | |
|         db->max_insns = CF_COUNT_MASK;
 | |
|     }
 | |
|     if (db->max_insns > TCG_MAX_INSNS) {
 | |
|         db->max_insns = TCG_MAX_INSNS;
 | |
|     }
 | |
|     if (db->singlestep_enabled || singlestep) {
 | |
|         db->max_insns = 1;
 | |
|     }
 | |
| 
 | |
|     ops->init_disas_context(db, cpu);
 | |
|     tcg_debug_assert(db->is_jmp == DISAS_NEXT);  /* no early exit */
 | |
| 
 | |
|     /* Reset the temp count so that we can identify leaks */
 | |
|     tcg_clear_temp_count();
 | |
| 
 | |
|     /* Start translating.  */
 | |
|     gen_tb_start(db->tb);
 | |
|     ops->tb_start(db, cpu);
 | |
|     tcg_debug_assert(db->is_jmp == DISAS_NEXT);  /* no early exit */
 | |
| 
 | |
|     while (true) {
 | |
|         db->num_insns++;
 | |
|         ops->insn_start(db, cpu);
 | |
|         tcg_debug_assert(db->is_jmp == DISAS_NEXT);  /* no early exit */
 | |
| 
 | |
|         /* Pass breakpoint hits to target for further processing */
 | |
|         if (unlikely(!QTAILQ_EMPTY(&cpu->breakpoints))) {
 | |
|             CPUBreakpoint *bp;
 | |
|             QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
 | |
|                 if (bp->pc == db->pc_next) {
 | |
|                     if (ops->breakpoint_check(db, cpu, bp)) {
 | |
|                         break;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             /* The breakpoint_check hook may use DISAS_TOO_MANY to indicate
 | |
|                that only one more instruction is to be executed.  Otherwise
 | |
|                it should use DISAS_NORETURN when generating an exception,
 | |
|                but may use a DISAS_TARGET_* value for Something Else.  */
 | |
|             if (db->is_jmp > DISAS_TOO_MANY) {
 | |
|                 break;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /* Disassemble one instruction.  The translate_insn hook should
 | |
|            update db->pc_next and db->is_jmp to indicate what should be
 | |
|            done next -- either exiting this loop or locate the start of
 | |
|            the next instruction.  */
 | |
|         if (db->num_insns == db->max_insns
 | |
|             && (tb_cflags(db->tb) & CF_LAST_IO)) {
 | |
|             /* Accept I/O on the last instruction.  */
 | |
|             gen_io_start();
 | |
|             ops->translate_insn(db, cpu);
 | |
|             gen_io_end();
 | |
|         } else {
 | |
|             ops->translate_insn(db, cpu);
 | |
|         }
 | |
| 
 | |
|         /* Stop translation if translate_insn so indicated.  */
 | |
|         if (db->is_jmp != DISAS_NEXT) {
 | |
|             break;
 | |
|         }
 | |
| 
 | |
|         /* Stop translation if the output buffer is full,
 | |
|            or we have executed all of the allowed instructions.  */
 | |
|         if (tcg_op_buf_full() || db->num_insns >= db->max_insns) {
 | |
|             db->is_jmp = DISAS_TOO_MANY;
 | |
|             break;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /* Emit code to exit the TB, as indicated by db->is_jmp.  */
 | |
|     ops->tb_stop(db, cpu);
 | |
|     gen_tb_end(db->tb, db->num_insns);
 | |
| 
 | |
|     /* The disas_log hook may use these values rather than recompute.  */
 | |
|     db->tb->size = db->pc_next - db->pc_first;
 | |
|     db->tb->icount = db->num_insns;
 | |
| 
 | |
| #ifdef DEBUG_DISAS
 | |
|     if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
 | |
|         && qemu_log_in_addr_range(db->pc_first)) {
 | |
|         qemu_log_lock();
 | |
|         qemu_log("----------------\n");
 | |
|         ops->disas_log(db, cpu);
 | |
|         qemu_log("\n");
 | |
|         qemu_log_unlock();
 | |
|     }
 | |
| #endif
 | |
| }
 |