Commit af352675 authored by Peter Maydell's avatar Peter Maydell
Browse files

Merge remote-tracking branch 'remotes/aurel/tags/pull-target-sh4-20171218' into staging



Queued target/sh4 patches

# gpg: Signature made Mon 18 Dec 2017 22:36:42 GMT
# gpg:                using RSA key 0x1388C0F899E8336B
# gpg: Good signature from "Aurelien Jarno <aurelien@aurel32.net>"
# gpg:                 aka "Aurelien Jarno <aurelien@jarno.fr>"
# gpg:                 aka "Aurelien Jarno <aurel32@debian.org>"
# gpg: WARNING: This key is not certified with sufficiently trusted signatures!
# gpg:          It is not certain that the signature belongs to the owner.
# Primary key fingerprint: 7746 2642 A9EF 94FD 0F77  196D BA9C 7806 1DDD 8C9B
#      Subkey fingerprint: 52BC 8695 BE34 F90A D7D4  0CB8 1388 C0F8 99E8 336B

* remotes/aurel/tags/pull-target-sh4-20171218:
  target/sh4: Convert to DisasContextBase
  target/sh4: Do not singlestep after exceptions
  target/sh4: Convert to DisasJumpType
  target/sh4: Use cmpxchg for movco when parallel_cpus
  target/sh4: fix TCG leak during gusa sequence
  target/sh4: add missing tcg_temp_free() in _decode_opc()

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents 03c1c09d 6f1c2af6
Loading
Loading
Loading
Loading
+15 −4
Original line number Diff line number Diff line
@@ -2679,6 +2679,8 @@ void cpu_loop(CPUSH4State *env)
    target_siginfo_t info;

    while (1) {
        bool arch_interrupt = true;

        cpu_exec_start(cs);
        trapnr = cpu_exec(cs);
        cpu_exec_end(cs);
@@ -2710,12 +2712,13 @@ void cpu_loop(CPUSH4State *env)
                int sig;

                sig = gdb_handlesig(cs, TARGET_SIGTRAP);
                if (sig)
                  {
                if (sig) {
                    info.si_signo = sig;
                    info.si_errno = 0;
                    info.si_code = TARGET_TRAP_BRKPT;
                    queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
                } else {
                    arch_interrupt = false;
                }
            }
            break;
@@ -2727,9 +2730,9 @@ void cpu_loop(CPUSH4State *env)
            info._sifields._sigfault._addr = env->tea;
            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
	    break;

        case EXCP_ATOMIC:
            cpu_exec_step_atomic(cs);
            arch_interrupt = false;
            break;
        default:
            printf ("Unhandled trap: 0x%x\n", trapnr);
@@ -2737,6 +2740,14 @@ void cpu_loop(CPUSH4State *env)
            exit(EXIT_FAILURE);
        }
        process_pending_signals (env);

        /* Most of the traps imply an exception or interrupt, which
           implies an REI instruction has been executed.  Which means
           that LDST (aka LOK_ADDR) should be cleared.  But there are
           a few exceptions for traps internal to QEMU.  */
        if (arch_interrupt) {
            env->lock_addr = -1;
        }
    }
}
#endif
+3 −1
Original line number Diff line number Diff line
@@ -188,7 +188,9 @@ typedef struct CPUSH4State {
    tlb_t itlb[ITLB_SIZE];	/* instruction translation table */
    tlb_t utlb[UTLB_SIZE];	/* unified translation table */

    uint32_t ldst;
    /* LDST = LOCK_ADDR != -1.  */
    uint32_t lock_addr;
    uint32_t lock_value;

    /* Fields up to this point are cleared by a CPU reset */
    struct {} end_reset_fields;
+1 −0
Original line number Diff line number Diff line
@@ -171,6 +171,7 @@ void superh_cpu_do_interrupt(CPUState *cs)
    env->spc = env->pc;
    env->sgr = env->gregs[15];
    env->sr |= (1u << SR_BL) | (1u << SR_MD) | (1u << SR_RB);
    env->lock_addr = -1;

    if (env->flags & DELAY_SLOT_MASK) {
        /* Branch instruction should be executed again before delay slot. */
+155 −118
Original line number Diff line number Diff line
@@ -25,28 +25,27 @@
#include "exec/exec-all.h"
#include "tcg-op.h"
#include "exec/cpu_ldst.h"

#include "exec/helper-proto.h"
#include "exec/helper-gen.h"

#include "exec/translator.h"
#include "trace-tcg.h"
#include "exec/log.h"


typedef struct DisasContext {
    struct TranslationBlock *tb;
    target_ulong pc;
    uint16_t opcode;
    DisasContextBase base;

    uint32_t tbflags;  /* should stay unmodified during the TB translation */
    uint32_t envflags; /* should stay in sync with env->flags using TCG ops */
    int bstate;
    int memidx;
    int gbank;
    int fbank;
    uint32_t delayed_pc;
    int singlestep_enabled;
    uint32_t features;
    int has_movcal;

    uint16_t opcode;

    bool has_movcal;
} DisasContext;

#if defined(CONFIG_USER_ONLY)
@@ -55,21 +54,18 @@ typedef struct DisasContext {
#define IS_USER(ctx) (!(ctx->tbflags & (1u << SR_MD)))
#endif

enum {
    BS_NONE     = 0, /* We go out of the TB without reaching a branch or an
                      * exception condition
                      */
    BS_STOP     = 1, /* We want to stop translation for any reason */
    BS_BRANCH   = 2, /* We reached a branch condition     */
    BS_EXCP     = 3, /* We reached an exception condition */
};
/* Target-specific values for ctx->base.is_jmp.  */
/* We want to exit back to the cpu loop for some reason.
   Usually this is to recognize interrupts immediately.  */
#define DISAS_STOP    DISAS_TARGET_0

/* global register indexes */
static TCGv cpu_gregs[32];
static TCGv cpu_sr, cpu_sr_m, cpu_sr_q, cpu_sr_t;
static TCGv cpu_pc, cpu_ssr, cpu_spc, cpu_gbr;
static TCGv cpu_vbr, cpu_sgr, cpu_dbr, cpu_mach, cpu_macl;
static TCGv cpu_pr, cpu_fpscr, cpu_fpul, cpu_ldst;
static TCGv cpu_pr, cpu_fpscr, cpu_fpul;
static TCGv cpu_lock_addr, cpu_lock_value;
static TCGv cpu_fregs[32];

/* internal register indexes */
@@ -147,8 +143,12 @@ void sh4_translate_init(void)
                                              offsetof(CPUSH4State,
                                                       delayed_cond),
                                              "_delayed_cond_");
    cpu_ldst = tcg_global_mem_new_i32(cpu_env,
				      offsetof(CPUSH4State, ldst), "_ldst_");
    cpu_lock_addr = tcg_global_mem_new_i32(cpu_env,
                                           offsetof(CPUSH4State, lock_addr),
                                           "_lock_addr_");
    cpu_lock_value = tcg_global_mem_new_i32(cpu_env,
                                            offsetof(CPUSH4State, lock_value),
                                            "_lock_value_");

    for (i = 0; i < 32; i++)
        cpu_fregs[i] = tcg_global_mem_new_i32(cpu_env,
@@ -209,7 +209,7 @@ static void gen_write_sr(TCGv src)
static inline void gen_save_cpu_state(DisasContext *ctx, bool save_pc)
{
    if (save_pc) {
        tcg_gen_movi_i32(cpu_pc, ctx->pc);
        tcg_gen_movi_i32(cpu_pc, ctx->base.pc_next);
    }
    if (ctx->delayed_pc != (uint32_t) -1) {
        tcg_gen_movi_i32(cpu_delayed_pc, ctx->delayed_pc);
@@ -227,11 +227,11 @@ static inline bool use_exit_tb(DisasContext *ctx)
static inline bool use_goto_tb(DisasContext *ctx, target_ulong dest)
{
    /* Use a direct jump if in same page and singlestep not enabled */
    if (unlikely(ctx->singlestep_enabled || use_exit_tb(ctx))) {
    if (unlikely(ctx->base.singlestep_enabled || use_exit_tb(ctx))) {
        return false;
    }
#ifndef CONFIG_USER_ONLY
    return (ctx->tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK);
    return (ctx->base.tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK);
#else
    return true;
#endif
@@ -242,10 +242,10 @@ static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
    if (use_goto_tb(ctx, dest)) {
        tcg_gen_goto_tb(n);
        tcg_gen_movi_i32(cpu_pc, dest);
        tcg_gen_exit_tb((uintptr_t)ctx->tb + n);
        tcg_gen_exit_tb((uintptr_t)ctx->base.tb + n);
    } else {
        tcg_gen_movi_i32(cpu_pc, dest);
        if (ctx->singlestep_enabled) {
        if (ctx->base.singlestep_enabled) {
            gen_helper_debug(cpu_env);
        } else if (use_exit_tb(ctx)) {
            tcg_gen_exit_tb(0);
@@ -253,6 +253,7 @@ static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
            tcg_gen_lookup_and_goto_ptr();
        }
    }
    ctx->base.is_jmp = DISAS_NORETURN;
}

static void gen_jump(DisasContext * ctx)
@@ -262,13 +263,14 @@ static void gen_jump(DisasContext * ctx)
	   delayed jump as immediate jump are conditinal jumps */
	tcg_gen_mov_i32(cpu_pc, cpu_delayed_pc);
        tcg_gen_discard_i32(cpu_delayed_pc);
        if (ctx->singlestep_enabled) {
        if (ctx->base.singlestep_enabled) {
            gen_helper_debug(cpu_env);
        } else if (use_exit_tb(ctx)) {
            tcg_gen_exit_tb(0);
        } else {
            tcg_gen_lookup_and_goto_ptr();
        }
        ctx->base.is_jmp = DISAS_NORETURN;
    } else {
	gen_goto_tb(ctx, 0, ctx->delayed_pc);
    }
@@ -298,8 +300,8 @@ static void gen_conditional_jump(DisasContext *ctx, target_ulong dest,
    tcg_gen_brcondi_i32(cond_not_taken, cpu_sr_t, 0, l1);
    gen_goto_tb(ctx, 0, dest);
    gen_set_label(l1);
    gen_goto_tb(ctx, 1, ctx->pc + 2);
    ctx->bstate = BS_BRANCH;
    gen_goto_tb(ctx, 1, ctx->base.pc_next + 2);
    ctx->base.is_jmp = DISAS_NORETURN;
}

/* Delayed conditional jump (bt or bf) */
@@ -322,11 +324,12 @@ static void gen_delayed_conditional_jump(DisasContext * ctx)
        gen_jump(ctx);

        gen_set_label(l1);
        ctx->base.is_jmp = DISAS_NEXT;
        return;
    }

    tcg_gen_brcondi_i32(TCG_COND_NE, ds, 0, l1);
    gen_goto_tb(ctx, 1, ctx->pc + 2);
    gen_goto_tb(ctx, 1, ctx->base.pc_next + 2);
    gen_set_label(l1);
    gen_jump(ctx);
}
@@ -463,7 +466,7 @@ static void _decode_opc(DisasContext * ctx)
	tcg_gen_mov_i32(cpu_delayed_pc, cpu_spc);
        ctx->envflags |= DELAY_SLOT_RTE;
	ctx->delayed_pc = (uint32_t) - 1;
        ctx->bstate = BS_STOP;
        ctx->base.is_jmp = DISAS_STOP;
	return;
    case 0x0058:		/* sets */
        tcg_gen_ori_i32(cpu_sr, cpu_sr, (1u << SR_S));
@@ -474,23 +477,23 @@ static void _decode_opc(DisasContext * ctx)
    case 0xfbfd:		/* frchg */
        CHECK_FPSCR_PR_0
	tcg_gen_xori_i32(cpu_fpscr, cpu_fpscr, FPSCR_FR);
	ctx->bstate = BS_STOP;
        ctx->base.is_jmp = DISAS_STOP;
	return;
    case 0xf3fd:		/* fschg */
        CHECK_FPSCR_PR_0
        tcg_gen_xori_i32(cpu_fpscr, cpu_fpscr, FPSCR_SZ);
	ctx->bstate = BS_STOP;
        ctx->base.is_jmp = DISAS_STOP;
	return;
    case 0xf7fd:                /* fpchg */
        CHECK_SH4A
        tcg_gen_xori_i32(cpu_fpscr, cpu_fpscr, FPSCR_PR);
        ctx->bstate = BS_STOP;
        ctx->base.is_jmp = DISAS_STOP;
        return;
    case 0x0009:		/* nop */
	return;
    case 0x001b:		/* sleep */
	CHECK_PRIVILEGED
        tcg_gen_movi_i32(cpu_pc, ctx->pc + 2);
        tcg_gen_movi_i32(cpu_pc, ctx->base.pc_next + 2);
        gen_helper_sleep(cpu_env);
	return;
    }
@@ -517,23 +520,24 @@ static void _decode_opc(DisasContext * ctx)
        /* Detect the start of a gUSA region.  If so, update envflags
           and end the TB.  This will allow us to see the end of the
           region (stored in R0) in the next TB.  */
        if (B11_8 == 15 && B7_0s < 0 && (tb_cflags(ctx->tb) & CF_PARALLEL)) {
        if (B11_8 == 15 && B7_0s < 0 &&
            (tb_cflags(ctx->base.tb) & CF_PARALLEL)) {
            ctx->envflags = deposit32(ctx->envflags, GUSA_SHIFT, 8, B7_0s);
            ctx->bstate = BS_STOP;
            ctx->base.is_jmp = DISAS_STOP;
        }
#endif
	tcg_gen_movi_i32(REG(B11_8), B7_0s);
	return;
    case 0x9000:		/* mov.w @(disp,PC),Rn */
	{
	    TCGv addr = tcg_const_i32(ctx->pc + 4 + B7_0 * 2);
            TCGv addr = tcg_const_i32(ctx->base.pc_next + 4 + B7_0 * 2);
            tcg_gen_qemu_ld_i32(REG(B11_8), addr, ctx->memidx, MO_TESW);
	    tcg_temp_free(addr);
	}
	return;
    case 0xd000:		/* mov.l @(disp,PC),Rn */
	{
	    TCGv addr = tcg_const_i32((ctx->pc + 4 + B7_0 * 4) & ~3);
            TCGv addr = tcg_const_i32((ctx->base.pc_next + 4 + B7_0 * 4) & ~3);
            tcg_gen_qemu_ld_i32(REG(B11_8), addr, ctx->memidx, MO_TESL);
	    tcg_temp_free(addr);
	}
@@ -543,13 +547,13 @@ static void _decode_opc(DisasContext * ctx)
	return;
    case 0xa000:		/* bra disp */
	CHECK_NOT_DELAY_SLOT
	ctx->delayed_pc = ctx->pc + 4 + B11_0s * 2;
        ctx->delayed_pc = ctx->base.pc_next + 4 + B11_0s * 2;
        ctx->envflags |= DELAY_SLOT;
	return;
    case 0xb000:		/* bsr disp */
	CHECK_NOT_DELAY_SLOT
	tcg_gen_movi_i32(cpu_pr, ctx->pc + 4);
	ctx->delayed_pc = ctx->pc + 4 + B11_0s * 2;
        tcg_gen_movi_i32(cpu_pr, ctx->base.pc_next + 4);
        ctx->delayed_pc = ctx->base.pc_next + 4 + B11_0s * 2;
        ctx->envflags |= DELAY_SLOT;
	return;
    }
@@ -601,6 +605,7 @@ static void _decode_opc(DisasContext * ctx)
	    tcg_gen_subi_i32(addr, REG(B11_8), 4);
            tcg_gen_qemu_st_i32(REG(B7_4), addr, ctx->memidx, MO_TEUL);
	    tcg_gen_mov_i32(REG(B11_8), addr);
        tcg_temp_free(addr);
	}
	return;
    case 0x6004:		/* mov.b @Rm+,Rn */
@@ -1176,22 +1181,22 @@ static void _decode_opc(DisasContext * ctx)
	return;
    case 0x8b00:		/* bf label */
	CHECK_NOT_DELAY_SLOT
        gen_conditional_jump(ctx, ctx->pc + 4 + B7_0s * 2, false);
        gen_conditional_jump(ctx, ctx->base.pc_next + 4 + B7_0s * 2, false);
	return;
    case 0x8f00:		/* bf/s label */
	CHECK_NOT_DELAY_SLOT
        tcg_gen_xori_i32(cpu_delayed_cond, cpu_sr_t, 1);
        ctx->delayed_pc = ctx->pc + 4 + B7_0s * 2;
        ctx->delayed_pc = ctx->base.pc_next + 4 + B7_0s * 2;
        ctx->envflags |= DELAY_SLOT_CONDITIONAL;
	return;
    case 0x8900:		/* bt label */
	CHECK_NOT_DELAY_SLOT
        gen_conditional_jump(ctx, ctx->pc + 4 + B7_0s * 2, true);
        gen_conditional_jump(ctx, ctx->base.pc_next + 4 + B7_0s * 2, true);
	return;
    case 0x8d00:		/* bt/s label */
	CHECK_NOT_DELAY_SLOT
        tcg_gen_mov_i32(cpu_delayed_cond, cpu_sr_t);
        ctx->delayed_pc = ctx->pc + 4 + B7_0s * 2;
        ctx->delayed_pc = ctx->base.pc_next + 4 + B7_0s * 2;
        ctx->envflags |= DELAY_SLOT_CONDITIONAL;
	return;
    case 0x8800:		/* cmp/eq #imm,R0 */
@@ -1278,7 +1283,8 @@ static void _decode_opc(DisasContext * ctx)
	}
	return;
    case 0xc700:		/* mova @(disp,PC),R0 */
	tcg_gen_movi_i32(REG(0), ((ctx->pc & 0xfffffffc) + 4 + B7_0 * 4) & ~3);
        tcg_gen_movi_i32(REG(0), ((ctx->base.pc_next & 0xfffffffc) +
                                  4 + B7_0 * 4) & ~3);
	return;
    case 0xcb00:		/* or #imm,R0 */
	tcg_gen_ori_i32(REG(0), REG(0), B7_0);
@@ -1304,7 +1310,7 @@ static void _decode_opc(DisasContext * ctx)
	    imm = tcg_const_i32(B7_0);
            gen_helper_trapa(cpu_env, imm);
	    tcg_temp_free(imm);
            ctx->bstate = BS_EXCP;
            ctx->base.is_jmp = DISAS_NORETURN;
	}
	return;
    case 0xc800:		/* tst #imm,R0 */
@@ -1372,13 +1378,13 @@ static void _decode_opc(DisasContext * ctx)
    switch (ctx->opcode & 0xf0ff) {
    case 0x0023:		/* braf Rn */
	CHECK_NOT_DELAY_SLOT
	tcg_gen_addi_i32(cpu_delayed_pc, REG(B11_8), ctx->pc + 4);
        tcg_gen_addi_i32(cpu_delayed_pc, REG(B11_8), ctx->base.pc_next + 4);
        ctx->envflags |= DELAY_SLOT;
	ctx->delayed_pc = (uint32_t) - 1;
	return;
    case 0x0003:		/* bsrf Rn */
	CHECK_NOT_DELAY_SLOT
	tcg_gen_movi_i32(cpu_pr, ctx->pc + 4);
        tcg_gen_movi_i32(cpu_pr, ctx->base.pc_next + 4);
	tcg_gen_add_i32(cpu_delayed_pc, REG(B11_8), cpu_pr);
        ctx->envflags |= DELAY_SLOT;
	ctx->delayed_pc = (uint32_t) - 1;
@@ -1401,7 +1407,7 @@ static void _decode_opc(DisasContext * ctx)
	return;
    case 0x400b:		/* jsr @Rn */
	CHECK_NOT_DELAY_SLOT
	tcg_gen_movi_i32(cpu_pr, ctx->pc + 4);
        tcg_gen_movi_i32(cpu_pr, ctx->base.pc_next + 4);
	tcg_gen_mov_i32(cpu_delayed_pc, REG(B11_8));
        ctx->envflags |= DELAY_SLOT;
	ctx->delayed_pc = (uint32_t) - 1;
@@ -1413,7 +1419,7 @@ static void _decode_opc(DisasContext * ctx)
            tcg_gen_andi_i32(val, REG(B11_8), 0x700083f3);
            gen_write_sr(val);
            tcg_temp_free(val);
            ctx->bstate = BS_STOP;
            ctx->base.is_jmp = DISAS_STOP;
        }
	return;
    case 0x4007:		/* ldc.l @Rm+,SR */
@@ -1425,7 +1431,7 @@ static void _decode_opc(DisasContext * ctx)
            gen_write_sr(val);
	    tcg_temp_free(val);
	    tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 4);
	    ctx->bstate = BS_STOP;
            ctx->base.is_jmp = DISAS_STOP;
	}
	return;
    case 0x0002:		/* stc SR,Rn */
@@ -1487,7 +1493,7 @@ static void _decode_opc(DisasContext * ctx)
    case 0x406a:		/* lds Rm,FPSCR */
	CHECK_FPU_ENABLED
        gen_helper_ld_fpscr(cpu_env, REG(B11_8));
	ctx->bstate = BS_STOP;
        ctx->base.is_jmp = DISAS_STOP;
	return;
    case 0x4066:		/* lds.l @Rm+,FPSCR */
	CHECK_FPU_ENABLED
@@ -1497,7 +1503,7 @@ static void _decode_opc(DisasContext * ctx)
	    tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 4);
            gen_helper_ld_fpscr(cpu_env, addr);
	    tcg_temp_free(addr);
	    ctx->bstate = BS_STOP;
            ctx->base.is_jmp = DISAS_STOP;
	}
	return;
    case 0x006a:		/* sts FPSCR,Rn */
@@ -1524,6 +1530,7 @@ static void _decode_opc(DisasContext * ctx)
            tcg_gen_qemu_ld_i32(val, REG(B11_8), ctx->memidx, MO_TEUL);
            gen_helper_movcal(cpu_env, REG(B11_8), val);
            tcg_gen_qemu_st_i32(REG(0), REG(B11_8), ctx->memidx, MO_TEUL);
            tcg_temp_free(val);
        }
        ctx->has_movcal = 1;
	return;
@@ -1547,31 +1554,64 @@ static void _decode_opc(DisasContext * ctx)
	return;
    case 0x0073:
        /* MOVCO.L
	       LDST -> T
               If (T == 1) R0 -> (Rn)
               0 -> LDST
        */
         *     LDST -> T
         *     If (T == 1) R0 -> (Rn)
         *     0 -> LDST
         *
         * The above description doesn't work in a parallel context.
         * Since we currently support no smp boards, this implies user-mode.
         * But we can still support the official mechanism while user-mode
         * is single-threaded.  */
        CHECK_SH4A
        {
            TCGLabel *label = gen_new_label();
            tcg_gen_mov_i32(cpu_sr_t, cpu_ldst);
	    tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_ldst, 0, label);
            TCGLabel *fail = gen_new_label();
            TCGLabel *done = gen_new_label();

            if ((tb_cflags(ctx->base.tb) & CF_PARALLEL)) {
                TCGv tmp;

                tcg_gen_brcond_i32(TCG_COND_NE, REG(B11_8),
                                   cpu_lock_addr, fail);
                tmp = tcg_temp_new();
                tcg_gen_atomic_cmpxchg_i32(tmp, REG(B11_8), cpu_lock_value,
                                           REG(0), ctx->memidx, MO_TEUL);
                tcg_gen_setcond_i32(TCG_COND_EQ, cpu_sr_t, tmp, cpu_lock_value);
                tcg_temp_free(tmp);
            } else {
                tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_lock_addr, -1, fail);
                tcg_gen_qemu_st_i32(REG(0), REG(B11_8), ctx->memidx, MO_TEUL);
	    gen_set_label(label);
	    tcg_gen_movi_i32(cpu_ldst, 0);
	    return;
                tcg_gen_movi_i32(cpu_sr_t, 1);
            }
            tcg_gen_br(done);

            gen_set_label(fail);
            tcg_gen_movi_i32(cpu_sr_t, 0);

            gen_set_label(done);
            tcg_gen_movi_i32(cpu_lock_addr, -1);
        }
        return;
    case 0x0063:
        /* MOVLI.L @Rm,R0
               1 -> LDST
               (Rm) -> R0
               When interrupt/exception
               occurred 0 -> LDST
        */
         *     1 -> LDST
         *     (Rm) -> R0
         *     When interrupt/exception
         *     occurred 0 -> LDST
         *
         * In a parallel context, we must also save the loaded value
         * for use with the cmpxchg that we'll use with movco.l.  */
        CHECK_SH4A
        tcg_gen_movi_i32(cpu_ldst, 0);
        if ((tb_cflags(ctx->base.tb) & CF_PARALLEL)) {
            TCGv tmp = tcg_temp_new();
            tcg_gen_mov_i32(tmp, REG(B11_8));
            tcg_gen_qemu_ld_i32(REG(0), REG(B11_8), ctx->memidx, MO_TESL);
        tcg_gen_movi_i32(cpu_ldst, 1);
            tcg_gen_mov_i32(cpu_lock_value, REG(0));
            tcg_gen_mov_i32(cpu_lock_addr, tmp);
            tcg_temp_free(tmp);
        } else {
            tcg_gen_qemu_ld_i32(REG(0), REG(B11_8), ctx->memidx, MO_TESL);
            tcg_gen_movi_i32(cpu_lock_addr, 0);
        }
        return;
    case 0x0093:		/* ocbi @Rn */
	{
@@ -1789,7 +1829,7 @@ static void _decode_opc(DisasContext * ctx)
    }
#if 0
    fprintf(stderr, "unknown instruction 0x%04x at pc 0x%08x\n",
	    ctx->opcode, ctx->pc);
            ctx->opcode, ctx->base.pc_next);
    fflush(stderr);
#endif
 do_illegal:
@@ -1801,7 +1841,7 @@ static void _decode_opc(DisasContext * ctx)
        gen_save_cpu_state(ctx, true);
        gen_helper_raise_illegal_instruction(cpu_env);
    }
    ctx->bstate = BS_EXCP;
    ctx->base.is_jmp = DISAS_NORETURN;
    return;

 do_fpu_disabled:
@@ -1811,7 +1851,7 @@ static void _decode_opc(DisasContext * ctx)
    } else {
        gen_helper_raise_fpu_disable(cpu_env);
    }
    ctx->bstate = BS_EXCP;
    ctx->base.is_jmp = DISAS_NORETURN;
    return;
}

@@ -1837,7 +1877,6 @@ static void decode_opc(DisasContext * ctx)
        ctx->envflags &= ~GUSA_MASK;

        tcg_gen_movi_i32(cpu_flags, ctx->envflags);
        ctx->bstate = BS_BRANCH;
        if (old_flags & DELAY_SLOT_CONDITIONAL) {
	    gen_delayed_conditional_jump(ctx);
        } else {
@@ -1864,8 +1903,8 @@ static int decode_gusa(DisasContext *ctx, CPUSH4State *env, int *pmax_insns)
    int mv_src, mt_dst, st_src, st_mop;
    TCGv op_arg;

    uint32_t pc = ctx->pc;
    uint32_t pc_end = ctx->tb->cs_base;
    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;
@@ -2189,13 +2228,13 @@ static int decode_gusa(DisasContext *ctx, CPUSH4State *env, int *pmax_insns)
    }

    /* If op_src is not a valid register, then op_arg was a constant.  */
    if (op_src < 0) {
    if (op_src < 0 && !TCGV_IS_UNUSED(op_arg)) {
        tcg_temp_free_i32(op_arg);
    }

    /* The entire region has been translated.  */
    ctx->envflags &= ~GUSA_MASK;
    ctx->pc = pc_end;
    ctx->base.pc_next = pc_end;
    return max_insns;

 fail:
@@ -2208,13 +2247,13 @@ static int decode_gusa(DisasContext *ctx, CPUSH4State *env, int *pmax_insns)
    ctx->envflags |= GUSA_EXCLUSIVE;
    gen_save_cpu_state(ctx, false);
    gen_helper_exclusive(cpu_env);
    ctx->bstate = BS_EXCP;
    ctx->base.is_jmp = DISAS_NORETURN;

    /* We're not executing an instruction, but we must report one for the
       purposes of accounting within the TB.  We might as well report the
       entire region consumed via ctx->pc so that it's immediately available
       in the disassembly dump.  */
    ctx->pc = pc_end;
       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
@@ -2228,16 +2267,16 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
    int max_insns;

    pc_start = tb->pc;
    ctx.pc = pc_start;
    ctx.base.pc_next = pc_start;
    ctx.tbflags = (uint32_t)tb->flags;
    ctx.envflags = tb->flags & TB_FLAG_ENVFLAGS_MASK;
    ctx.bstate = BS_NONE;
    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.tb = tb;
    ctx.singlestep_enabled = cs->singlestep_enabled;
    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)) &&
@@ -2252,11 +2291,11 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)

    /* Since the ISA is fixed-width, we can bound by the number
       of instructions remaining on the page.  */
    num_insns = -(ctx.pc | TARGET_PAGE_MASK) / 2;
    num_insns = -(ctx.base.pc_next | TARGET_PAGE_MASK) / 2;
    max_insns = MIN(max_insns, num_insns);

    /* Single stepping means just that.  */
    if (ctx.singlestep_enabled || singlestep) {
    if (ctx.base.singlestep_enabled || singlestep) {
        max_insns = 1;
    }

@@ -2269,22 +2308,22 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
    }
#endif

    while (ctx.bstate == BS_NONE
    while (ctx.base.is_jmp == DISAS_NEXT
           && num_insns < max_insns
           && !tcg_op_buf_full()) {
        tcg_gen_insn_start(ctx.pc, ctx.envflags);
        tcg_gen_insn_start(ctx.base.pc_next, ctx.envflags);
        num_insns++;

        if (unlikely(cpu_breakpoint_test(cs, ctx.pc, BP_ANY))) {
        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.bstate = BS_EXCP;
            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.pc += 2;
            ctx.base.pc_next += 2;
            break;
        }

@@ -2292,9 +2331,9 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
            gen_io_start();
        }

        ctx.opcode = cpu_lduw_code(env, ctx.pc);
        ctx.opcode = cpu_lduw_code(env, ctx.base.pc_next);
	decode_opc(&ctx);
	ctx.pc += 2;
        ctx.base.pc_next += 2;
    }
    if (tb_cflags(tb) & CF_LAST_IO) {
        gen_io_end();
@@ -2305,30 +2344,28 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
        ctx.envflags &= ~GUSA_MASK;
    }

    if (cs->singlestep_enabled) {
    switch (ctx.base.is_jmp) {
    case DISAS_STOP:
        gen_save_cpu_state(&ctx, true);
        if (ctx.base.singlestep_enabled) {
            gen_helper_debug(cpu_env);
        } else {
	switch (ctx.bstate) {
        case BS_STOP:
            gen_save_cpu_state(&ctx, true);
            tcg_gen_exit_tb(0);
        }
        break;
        case BS_NONE:
    case DISAS_NEXT:
        gen_save_cpu_state(&ctx, false);
            gen_goto_tb(&ctx, 0, ctx.pc);
        gen_goto_tb(&ctx, 0, ctx.base.pc_next);
        break;
        case BS_EXCP:
            /* fall through */
        case BS_BRANCH:
        default:
    case DISAS_NORETURN:
        break;
	}
    default:
        g_assert_not_reached();
    }

    gen_tb_end(tb, num_insns);

    tb->size = ctx.pc - pc_start;
    tb->size = ctx.base.pc_next - pc_start;
    tb->icount = num_insns;

#ifdef DEBUG_DISAS
@@ -2336,7 +2373,7 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
        && 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.pc - pc_start);
        log_target_disas(cs, pc_start, ctx.base.pc_next - pc_start);
	qemu_log("\n");
        qemu_log_unlock();
    }