Commit 2ace7e55 authored by Richard Henderson's avatar Richard Henderson Committed by Richard Henderson
Browse files

target-alpha: Implement more CALL_PAL values inline.



In particular, SWPIPL is used quite a lot by the Linux kernel.
Doing this inline makes it significantly easier to step through
without the debugger getting confused by the mode switch.

Signed-off-by: default avatarRichard Henderson <rth@twiddle.net>
parent 6a80e088
Loading
Loading
Loading
Loading
+108 −32
Original line number Diff line number Diff line
@@ -85,8 +85,10 @@ static TCGv cpu_pc;
static TCGv cpu_lock_addr;
static TCGv cpu_lock_st_addr;
static TCGv cpu_lock_value;
#ifdef CONFIG_USER_ONLY
static TCGv cpu_uniq;
static TCGv cpu_unique;
#ifndef CONFIG_USER_ONLY
static TCGv cpu_sysval;
static TCGv cpu_usp;
#endif

/* register names */
@@ -131,9 +133,13 @@ static void alpha_translate_init(void)
					    offsetof(CPUState, lock_value),
					    "lock_value");

#ifdef CONFIG_USER_ONLY
    cpu_uniq = tcg_global_mem_new_i64(TCG_AREG0,
                                      offsetof(CPUState, unique), "uniq");
    cpu_unique = tcg_global_mem_new_i64(TCG_AREG0,
                                        offsetof(CPUState, unique), "unique");
#ifndef CONFIG_USER_ONLY
    cpu_sysval = tcg_global_mem_new_i64(TCG_AREG0,
                                        offsetof(CPUState, sysval), "sysval");
    cpu_usp = tcg_global_mem_new_i64(TCG_AREG0,
                                     offsetof(CPUState, usp), "usp");
#endif

    /* register helpers */
@@ -1464,6 +1470,101 @@ static void gen_rx(int ra, int set)
    tcg_temp_free_i32(tmp);
}

static ExitStatus gen_call_pal(DisasContext *ctx, int palcode)
{
    /* We're emulating OSF/1 PALcode.  Many of these are trivial access
       to internal cpu registers.  */

    /* Unprivileged PAL call */
    if (palcode >= 0x80 && palcode < 0xC0) {
        switch (palcode) {
        case 0x86:
            /* IMB */
            /* No-op inside QEMU.  */
            break;
        case 0x9E:
            /* RDUNIQUE */
            tcg_gen_mov_i64(cpu_ir[IR_V0], cpu_unique);
            break;
        case 0x9F:
            /* WRUNIQUE */
            tcg_gen_mov_i64(cpu_unique, cpu_ir[IR_A0]);
            break;
        default:
            return gen_excp(ctx, EXCP_CALL_PAL, palcode & 0xbf);
        }
        return NO_EXIT;
    }

#ifndef CONFIG_USER_ONLY
    /* Privileged PAL code */
    if (palcode < 0x40 && (ctx->tb->flags & TB_FLAGS_USER_MODE) == 0) {
        switch (palcode) {
        case 0x01:
            /* CFLUSH */
            /* No-op inside QEMU.  */
            break;
        case 0x02:
            /* DRAINA */
            /* No-op inside QEMU.  */
            break;
        case 0x2D:
            /* WRVPTPTR */
            tcg_gen_st_i64(cpu_ir[IR_A0], cpu_env, offsetof(CPUState, vptptr));
            break;
        case 0x31:
            /* WRVAL */
            tcg_gen_mov_i64(cpu_sysval, cpu_ir[IR_A0]);
            break;
        case 0x32:
            /* RDVAL */
            tcg_gen_mov_i64(cpu_ir[IR_V0], cpu_sysval);
            break;

        case 0x35: {
            /* SWPIPL */
            TCGv tmp;

            /* Note that we already know we're in kernel mode, so we know
               that PS only contains the 3 IPL bits.  */
            tcg_gen_ld8u_i64(cpu_ir[IR_V0], cpu_env, offsetof(CPUState, ps));

            /* But make sure and store only the 3 IPL bits from the user.  */
            tmp = tcg_temp_new();
            tcg_gen_andi_i64(tmp, cpu_ir[IR_A0], PS_INT_MASK);
            tcg_gen_st8_i64(tmp, cpu_env, offsetof(CPUState, ps));
            tcg_temp_free(tmp);
            break;
        }

        case 0x36:
            /* RDPS */
            tcg_gen_ld8u_i64(cpu_ir[IR_V0], cpu_env, offsetof(CPUState, ps));
            break;
        case 0x38:
            /* WRUSP */
            tcg_gen_mov_i64(cpu_usp, cpu_ir[IR_A0]);
            break;
        case 0x3A:
            /* RDUSP */
            tcg_gen_mov_i64(cpu_ir[IR_V0], cpu_usp);
            break;
        case 0x3C:
            /* WHAMI */
            tcg_gen_ld32s_i64(cpu_ir[IR_V0], cpu_env,
                              offsetof(CPUState, cpu_index));
            break;

        default:
            return gen_excp(ctx, EXCP_CALL_PAL, palcode & 0x3f);
        }
        return NO_EXIT;
    }
#endif

    return gen_invalid(ctx);
}

#ifndef CONFIG_USER_ONLY

#define PR_BYTE         0x100000
@@ -1582,33 +1683,8 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
    switch (opc) {
    case 0x00:
        /* CALL_PAL */
#ifdef CONFIG_USER_ONLY
        if (palcode == 0x9E) {
            /* RDUNIQUE */
            tcg_gen_mov_i64(cpu_ir[IR_V0], cpu_uniq);
            break;
        } else if (palcode == 0x9F) {
            /* WRUNIQUE */
            tcg_gen_mov_i64(cpu_uniq, cpu_ir[IR_A0]);
            break;
        }
#endif
        if (palcode >= 0x80 && palcode < 0xC0) {
            /* Unprivileged PAL call */
            ret = gen_excp(ctx, EXCP_CALL_PAL, palcode & 0xBF);
        ret = gen_call_pal(ctx, palcode);
        break;
        }
#ifndef CONFIG_USER_ONLY
        if (palcode < 0x40) {
            /* Privileged PAL code */
            if (ctx->mem_idx != MMU_KERNEL_IDX) {
                goto invalid_opc;
            }
            ret = gen_excp(ctx, EXCP_CALL_PAL, palcode & 0x3F);
        }
#endif
        /* Invalid PAL call */
        goto invalid_opc;
    case 0x01:
        /* OPC01 */
        goto invalid_opc;