From patchwork Thu Sep 7 18:50:57 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Henderson X-Patchwork-Id: 111968 Delivered-To: patch@linaro.org Received: by 10.140.94.239 with SMTP id g102csp497045qge; Thu, 7 Sep 2017 11:55:03 -0700 (PDT) X-Received: by 10.223.164.206 with SMTP id h14mr195819wrb.25.1504810503373; Thu, 07 Sep 2017 11:55:03 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1504810503; cv=none; d=google.com; s=arc-20160816; b=U7jCp6A3IWH73sJcCZo3lWBlJoj5arH1b6hD++WU6K8sBexeJDiReUDEr4dmOkoCY6 0U3hlrOBXYxZISSpvR02MEJ3J9jd7l7k6p2TaGVy6KHjjA3ipTHW8L1Dzf9vtrFol45o R3Pzh69dq5EX1amlzb+iQR6rc99UujBAizJYz90pk+1MTDNEgg6Wd0jXykwWwiAp/Sp2 yJeGpW7LmcoXWOh3b6i4nHeWWVT8WmZYBFWB0blrRglSniPeLEVzy3QbFqW+aC0RSosv jDcURwbbAdyCpMgacD79T2RXu2Z0LeurUVsQkh/Dy2kV0U1nmfYdk5fA1N40qI9DJSL4 ebfg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:cc:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:subject:references:in-reply-to :message-id:date:to:from:dkim-signature:arc-authentication-results; bh=jYYKiAzIoFqTuiYuHu7WB/C983bpNQLGILsQ08P+xLU=; b=SOaWwYhxGd6XiamOaP/GAB5a8qsUHUgfafPuLhZK9AMaoL2o8SSTdQIwDteqQFXdSh bX1gUyBlg5nzB/xMfbXfBElHqB6tuFNsHUS4Nne8SY9gSUfnPoAukaKXzTZEL360Ghhk 1a2GJtMD6AhnyZ/D6LT83Ucdgis9oHgwZLjcUfQcfNThQEf1YCkswp8c47stD4iP1gh/ 9/K1cnFwx/Ep2L1p31eZh3q5ANi17OTrVveRai0/BbDrxnTAN+dZm0OWHAtX0bQcMBPV TkoYBwTfiGHcQ/MLykka9WpZ2+Y0xJxQqML3fU/v0MIOeSvmk5XSIAtzSaE2YwmoomVY JCKQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@linaro.org header.s=google header.b=L9oXoSq2; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 2001:4830:134:3::11 as permitted sender) smtp.mailfrom=qemu-devel-bounces+patch=linaro.org@nongnu.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from lists.gnu.org (lists.gnu.org. [2001:4830:134:3::11]) by mx.google.com with ESMTPS id b66si6664wmf.118.2017.09.07.11.55.03 for (version=TLS1 cipher=AES128-SHA bits=128/128); Thu, 07 Sep 2017 11:55:03 -0700 (PDT) Received-SPF: pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 2001:4830:134:3::11 as permitted sender) client-ip=2001:4830:134:3::11; Authentication-Results: mx.google.com; dkim=fail header.i=@linaro.org header.s=google header.b=L9oXoSq2; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 2001:4830:134:3::11 as permitted sender) smtp.mailfrom=qemu-devel-bounces+patch=linaro.org@nongnu.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from localhost ([::1]:41780 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dq1x8-00037w-5d for patch@linaro.org; Thu, 07 Sep 2017 14:55:02 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:54202) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dq1tR-0000F0-K2 for qemu-devel@nongnu.org; Thu, 07 Sep 2017 14:51:19 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dq1tL-0000XV-Qi for qemu-devel@nongnu.org; Thu, 07 Sep 2017 14:51:13 -0400 Received: from mail-pg0-x232.google.com ([2607:f8b0:400e:c05::232]:33555) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1dq1tL-0000X8-Ie for qemu-devel@nongnu.org; Thu, 07 Sep 2017 14:51:07 -0400 Received: by mail-pg0-x232.google.com with SMTP id t3so1011282pgt.0 for ; Thu, 07 Sep 2017 11:51:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=jYYKiAzIoFqTuiYuHu7WB/C983bpNQLGILsQ08P+xLU=; b=L9oXoSq2DECuoNTmPYiJrBxhVEXZjIc9k9ATFvMVK/lkF0V+6K6/GVrG8OMAxRsnu+ nG8maRpFw9w/DYrKpxBV4+zyFbOOK6TOvADFF8bN3uLapy/jpiZZPqZr3oxgSFpJ79YY RHvypP+VSJ0Uq8XqTl/wP7MvraAz8o5Zg6pOA= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=jYYKiAzIoFqTuiYuHu7WB/C983bpNQLGILsQ08P+xLU=; b=J5zHP3Uuay3ZCBa55xUFEEaqmcg1UZqWchxhxmu+GB9jc80/CNQx6PJVeb2vQ+9Eut QetY0iA3B9pY4rQxnf8Vw7KoZnEAd2jK835x2XLt+FjbjAQ9+QPgeBS7kYXuhtpQ3ep2 rVkFAYIVpDVA1Z2kcnQY7fyjgRPJTb/lt8JlQgRKnQmngNFLViKT7DgbfC5YRQOwNdCl RCWfkmetgJNa/Ul8qdHNu76TG60uW+2nyaKW5YZ5l4K38G5kEI2tqjh5oS/Zixqi3zXQ WbpKOGsz2iTEVHweQ7dw+Sy8KwKdJ0qy2GzVtBP2l9xtkCeKhBpPd1Aq625CIvPzkoK5 GlQA== X-Gm-Message-State: AHPjjUgLxRM7RQmMXQGtDWg+17m4jlynx8Gq9+1hvs/dZvjlWHOQA1Ro gT26VUMdYIdAkUrFA/birg== X-Google-Smtp-Source: ADKCNb4UTrOyIFVlHybwFTK+9HCXZVjleW8bbYPFbYbCgAcV7X4N0XMGttkp/qcHxC1uTU/dnLEh9w== X-Received: by 10.98.224.92 with SMTP id f89mr363499pfh.138.1504810266049; Thu, 07 Sep 2017 11:51:06 -0700 (PDT) Received: from pike.twiddle.net (97-126-108-236.tukw.qwest.net. [97.126.108.236]) by smtp.gmail.com with ESMTPSA id l74sm481401pfi.9.2017.09.07.11.51.04 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Thu, 07 Sep 2017 11:51:04 -0700 (PDT) From: Richard Henderson To: qemu-devel@nongnu.org Date: Thu, 7 Sep 2017 11:50:57 -0700 Message-Id: <20170907185057.23421-6-richard.henderson@linaro.org> X-Mailer: git-send-email 2.13.5 In-Reply-To: <20170907185057.23421-1-richard.henderson@linaro.org> References: <20170907185057.23421-1-richard.henderson@linaro.org> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2607:f8b0:400e:c05::232 Subject: [Qemu-devel] [PATCH v2 5/5] target/sh4: Convert to TranslatorOps X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: aurelien@aurel32.net, Richard Henderson Errors-To: qemu-devel-bounces+patch=linaro.org@nongnu.org Sender: "Qemu-devel" From: Richard Henderson Signed-off-by: Richard Henderson --- target/sh4/translate.c | 272 ++++++++++++++++++++++++++----------------------- 1 file changed, 147 insertions(+), 125 deletions(-) -- 2.13.5 diff --git a/target/sh4/translate.c b/target/sh4/translate.c index ed462bab12..ca6589047b 100644 --- a/target/sh4/translate.c +++ b/target/sh4/translate.c @@ -34,6 +34,9 @@ typedef struct DisasContext { DisasContextBase base; +#ifdef CONFIG_USER_ONLY + TranslatorOps ops; +#endif uint32_t tbflags; /* should stay unmodified during the TB translation */ uint32_t envflags; /* should stay in sync with env->flags using TCG ops */ @@ -1892,6 +1895,100 @@ static void decode_opc(DisasContext * ctx) } #ifdef CONFIG_USER_ONLY +static void sh4_tr_translate_gusa(DisasContextBase *dcbase, CPUState *cpu); +#endif + +static int sh4_tr_init_disas_context(DisasContextBase *dcbase, + CPUState *cpu, int max_insns) +{ + DisasContext *ctx = container_of(dcbase, DisasContext, base); + CPUSH4State *env = cpu->env_ptr; + uint32_t pc = ctx->base.pc_next; + uint32_t tbflags = ctx->base.tb->flags; + int bound; + + ctx->tbflags = tbflags; + ctx->envflags = tbflags & TB_FLAG_ENVFLAGS_MASK; + ctx->memidx = (tbflags & (1u << SR_MD)) == 0 ? 1 : 0; + /* We don't know if the delayed pc came from a dynamic or static branch, + so assume it is a dynamic branch. */ + ctx->delayed_pc = -1; /* use delayed pc from env pointer */ + ctx->features = env->features; + ctx->has_movcal = (tbflags & TB_FLAG_PENDING_MOVCA) != 0; + ctx->gbank = ((tbflags & (1 << SR_MD)) && + (tbflags & (1 << SR_RB))) * 0x10; + ctx->fbank = tbflags & FPSCR_FR ? 0x10 : 0; + + /* Since the ISA is fixed-width, we can bound by the number + of instructions remaining on the page. */ + bound = -(pc | TARGET_PAGE_MASK) / 2; + max_insns = MIN(max_insns, bound); + +#ifdef CONFIG_USER_ONLY + if (tbflags & GUSA_MASK) { + uint32_t pc_end = ctx->base.tb->cs_base; + int backup = sextract32(ctx->tbflags, GUSA_SHIFT, 8); + int gusa_insns = -backup / 2; + + if (pc != pc_end + backup || gusa_insns < 2) { + /* This is a malformed gUSA region. Don't do anything special, + since the interpreter is likely to get confused. */ + ctx->envflags &= ~GUSA_MASK; + } else if (tbflags & GUSA_EXCLUSIVE) { + /* Regardless of single-stepping or the end of the page, + we must complete execution of the gUSA region while + holding the exclusive lock. */ + max_insns = gusa_insns; + } else { + /* Attempt to translate to an atomic insn. */ + ctx->ops.translate_insn = sh4_tr_translate_gusa; + } + } +#endif + + return max_insns; +} + +static void sh4_tr_tb_start(DisasContextBase *dcbase, CPUState *cpu) +{ +} + +static void sh4_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu) +{ + DisasContext *ctx = container_of(dcbase, DisasContext, base); + + tcg_gen_insn_start(ctx->base.pc_next, ctx->envflags); +} + +static bool sh4_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cpu, + const CPUBreakpoint *bp) +{ + DisasContext *ctx = container_of(dcbase, DisasContext, base); + + /* We have hit a breakpoint - make sure PC is up-to-date */ + gen_save_cpu_state(ctx, true); + gen_helper_debug(cpu_env); + ctx->base.is_jmp = DISAS_NORETURN; + + /* 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. */ + ctx->base.pc_next += 2; + return true; +} + +static void sh4_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) +{ + DisasContext *ctx = container_of(dcbase, DisasContext, base); + CPUSH4State *env = cpu->env_ptr; + + ctx->opcode = cpu_lduw_code(env, ctx->base.pc_next); + decode_opc(ctx); + ctx->base.pc_next += 2; +} + +#ifdef CONFIG_USER_ONLY /* For uniprocessors, SH4 uses optimistic restartable atomic sequences. Upon an interrupt, a real kernel would simply notice magic values in the registers and reset the PC to the start of the sequence. @@ -1901,35 +1998,23 @@ static void decode_opc(DisasContext * ctx) any sequence via cpu_exec_step_atomic, we can recognize the "normal" sequences and transform them into atomic operations as seen by the host. */ -static int decode_gusa(DisasContext *ctx, CPUSH4State *env, int *pmax_insns) +static void sh4_tr_translate_gusa(DisasContextBase *dcbase, CPUState *cpu) { + DisasContext *ctx = container_of(dcbase, DisasContext, base); + CPUSH4State *env = cpu->env_ptr; + + int backup = sextract32(ctx->tbflags, GUSA_SHIFT, 8); + int max_insns = -backup / 2; + uint32_t pc = ctx->base.pc_next; + uint32_t pc_end = ctx->base.tb->cs_base; + uint16_t insns[5]; int ld_adr, ld_dst, ld_mop; int op_dst, op_src, op_opc; int mv_src, mt_dst, st_src, st_mop; TCGv op_arg; - - uint32_t pc = ctx->base.pc_next; - uint32_t pc_end = ctx->base.tb->cs_base; - int backup = sextract32(ctx->tbflags, GUSA_SHIFT, 8); - int max_insns = (pc_end - pc) / 2; int i; - if (pc != pc_end + backup || max_insns < 2) { - /* This is a malformed gUSA region. Don't do anything special, - since the interpreter is likely to get confused. */ - ctx->envflags &= ~GUSA_MASK; - return 0; - } - - if (ctx->tbflags & GUSA_EXCLUSIVE) { - /* Regardless of single-stepping or the end of the page, - we must complete execution of the gUSA region while - holding the exclusive lock. */ - *pmax_insns = max_insns; - return 0; - } - /* The state machine below will consume only a few insns. If there are more than that in a region, fail now. */ if (max_insns > ARRAY_SIZE(insns)) { @@ -2146,7 +2231,6 @@ static int decode_gusa(DisasContext *ctx, CPUSH4State *env, int *pmax_insns) /* * Emit the operation. */ - tcg_gen_insn_start(pc, ctx->envflags); switch (op_opc) { case -1: /* No operation found. Look for exchange pattern. */ @@ -2239,9 +2323,13 @@ static int decode_gusa(DisasContext *ctx, CPUSH4State *env, int *pmax_insns) } /* The entire region has been translated. */ - ctx->envflags &= ~GUSA_MASK; ctx->base.pc_next = pc_end; - return max_insns; + ctx->base.num_insns = max_insns; + + /* Revert to normal parsing for the rest of the TB. */ + ctx->envflags &= ~GUSA_MASK; + ctx->ops.translate_insn = sh4_tr_translate_insn; + return; fail: qemu_log_mask(LOG_UNIMP, "Unrecognized gUSA sequence %08x-%08x\n", @@ -2249,7 +2337,6 @@ static int decode_gusa(DisasContext *ctx, CPUSH4State *env, int *pmax_insns) /* Restart with the EXCLUSIVE bit set, within a TB run via cpu_exec_step_atomic holding the exclusive lock. */ - tcg_gen_insn_start(pc, ctx->envflags); ctx->envflags |= GUSA_EXCLUSIVE; gen_save_cpu_state(ctx, false); gen_helper_exclusive(cpu_env); @@ -2260,129 +2347,64 @@ static int decode_gusa(DisasContext *ctx, CPUSH4State *env, int *pmax_insns) entire region consumed via ctx->base.pc_next so that it's immediately available in the disassembly dump. */ ctx->base.pc_next = pc_end; - return 1; } #endif -void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb) +static void sh4_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) { - CPUSH4State *env = cs->env_ptr; - DisasContext ctx; - target_ulong pc_start; - int num_insns; - int max_insns; - - pc_start = tb->pc; - ctx.base.pc_next = pc_start; - ctx.tbflags = (uint32_t)tb->flags; - ctx.envflags = tb->flags & TB_FLAG_ENVFLAGS_MASK; - ctx.base.is_jmp = DISAS_NEXT; - ctx.memidx = (ctx.tbflags & (1u << SR_MD)) == 0 ? 1 : 0; - /* We don't know if the delayed pc came from a dynamic or static branch, - so assume it is a dynamic branch. */ - ctx.delayed_pc = -1; /* use delayed pc from env pointer */ - ctx.base.tb = tb; - ctx.base.singlestep_enabled = cs->singlestep_enabled; - ctx.features = env->features; - ctx.has_movcal = (ctx.tbflags & TB_FLAG_PENDING_MOVCA); - ctx.gbank = ((ctx.tbflags & (1 << SR_MD)) && - (ctx.tbflags & (1 << SR_RB))) * 0x10; - ctx.fbank = ctx.tbflags & FPSCR_FR ? 0x10 : 0; - - max_insns = tb->cflags & CF_COUNT_MASK; - if (max_insns == 0) { - max_insns = CF_COUNT_MASK; - } - max_insns = MIN(max_insns, TCG_MAX_INSNS); - - /* Since the ISA is fixed-width, we can bound by the number - of instructions remaining on the page. */ - num_insns = -(ctx.base.pc_next | TARGET_PAGE_MASK) / 2; - max_insns = MIN(max_insns, num_insns); + DisasContext *ctx = container_of(dcbase, DisasContext, base); - /* Single stepping means just that. */ - if (ctx.base.singlestep_enabled || singlestep) { - max_insns = 1; - } - - gen_tb_start(tb); - num_insns = 0; - -#ifdef CONFIG_USER_ONLY - if (ctx.tbflags & GUSA_MASK) { - num_insns = decode_gusa(&ctx, env, &max_insns); - } -#endif - - while (ctx.base.is_jmp == DISAS_NEXT - && num_insns < max_insns - && !tcg_op_buf_full()) { - tcg_gen_insn_start(ctx.base.pc_next, ctx.envflags); - num_insns++; - - if (unlikely(cpu_breakpoint_test(cs, ctx.base.pc_next, BP_ANY))) { - /* We have hit a breakpoint - make sure PC is up-to-date */ - gen_save_cpu_state(&ctx, true); - gen_helper_debug(cpu_env); - ctx.base.is_jmp = DISAS_NORETURN; - /* 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. */ - ctx.base.pc_next += 2; - break; - } - - if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) { - gen_io_start(); - } - - ctx.opcode = cpu_lduw_code(env, ctx.base.pc_next); - decode_opc(&ctx); - ctx.base.pc_next += 2; - } - if (tb->cflags & CF_LAST_IO) { - gen_io_end(); - } - - if (ctx.tbflags & GUSA_EXCLUSIVE) { + if (ctx->tbflags & GUSA_EXCLUSIVE) { /* Ending the region of exclusivity. Clear the bits. */ - ctx.envflags &= ~GUSA_MASK; + ctx->envflags &= ~GUSA_MASK; } - switch (ctx.base.is_jmp) { + switch (ctx->base.is_jmp) { case DISAS_STOP: - gen_save_cpu_state(&ctx, true); - if (ctx.base.singlestep_enabled) { + gen_save_cpu_state(ctx, true); + if (ctx->base.singlestep_enabled) { gen_helper_debug(cpu_env); } else { tcg_gen_exit_tb(0); } break; - case DISAS_NEXT: - gen_save_cpu_state(&ctx, false); - gen_goto_tb(&ctx, 0, ctx.base.pc_next); + case DISAS_TOO_MANY: + gen_save_cpu_state(ctx, false); + gen_goto_tb(ctx, 0, ctx->base.pc_next); break; case DISAS_NORETURN: break; default: g_assert_not_reached(); } +} - gen_tb_end(tb, num_insns); +static void sh4_tr_disas_log(const DisasContextBase *dcbase, CPUState *cpu) +{ + qemu_log("IN: %s\n", lookup_symbol(dcbase->pc_first)); + log_target_disas(cpu, dcbase->pc_first, dcbase->tb->size, 0); +} - tb->size = ctx.base.pc_next - pc_start; - tb->icount = num_insns; +void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb) +{ + static const TranslatorOps ops = { + .init_disas_context = sh4_tr_init_disas_context, + .tb_start = sh4_tr_tb_start, + .insn_start = sh4_tr_insn_start, + .breakpoint_check = sh4_tr_breakpoint_check, + .translate_insn = sh4_tr_translate_insn, + .tb_stop = sh4_tr_tb_stop, + .disas_log = sh4_tr_disas_log, + }; + DisasContext ctx; -#ifdef DEBUG_DISAS - if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM) - && qemu_log_in_addr_range(pc_start)) { - qemu_log_lock(); - qemu_log("IN:\n"); /* , lookup_symbol(pc_start)); */ - log_target_disas(cs, pc_start, ctx.base.pc_next - pc_start, 0); - qemu_log("\n"); - qemu_log_unlock(); - } +#ifdef CONFIG_USER_ONLY + /* We may switch the translate_insn hook in init_disas_context + and within translate_insn itself. */ + ctx.ops = ops; + translator_loop(&ctx.ops, &ctx.base, cpu, tb); +#else + translator_loop(&ops, &ctx.base, cpu, tb); #endif }