qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH v1 25/43] target/loongarch: Add LoongArch CSR instruction


From: yangxiaojuan
Subject: Re: [PATCH v1 25/43] target/loongarch: Add LoongArch CSR instruction
Date: Thu, 21 Apr 2022 17:15:25 +0800
User-agent: Mozilla/5.0 (X11; Linux loongarch64; rv:68.0) Gecko/20100101 Thunderbird/68.7.0


On 2022/4/20 上午1:05, Richard Henderson wrote:
You'd use a store, just like you were already doing in trans_csrwr.

But here's how I'd improve this.  For avoidance of doubt, all of this would go in trans_priviledged.c.inc -- there's no use of csr_offsets[] outside of that file.

Thanks you very much,  I had tested this with bios,  it worked well, and I have two questions.

1. CSRFL_IO,   how to use it.   I don't understand  CPUState options  'can_do_Io',
2./* fall through */,   this may have warning,  should we care about this?

Thanks.
Xiaojuan
r~

----


typedef void (*GenCSRRead)(TCGv dest, TCGv_ptr env);
typedef void (*GenCSRWrite)(TCGv dest, TCGv_ptr env, TCGv src);

typedef struct {
    int offset;
    int flags;
    GenCSRRead readfn;
    GenCSRWrite writefn;
} CSRInfo;

enum {
    CSRFL_READONLY  = (1 << 0),
    CSRFL_EXITTB    = (1 << 1),
    CSRFL_IO        = (1 << 2),
};

#define CSR_OFF_FUNCS(NAME, FL, RD, WR) \
    [LOONGARCH_CSR_##NAME] = {                             \
        .offset = offsetof(CPULoongArchState, CSR_##NAME), \
        .flags = FL, .readfn = RD, .writefn = WR           \
    }
#define CSR_OFF_FLAGS(NAME, FL) \
    CSR_OFF_FUNCS(NAME, FL, NULL, NULL)
#define CSR_OFF(NAME) \
    CSR_OFF_FLAGS(NAME, 0)

static const CSRInfo csr_info[] = {
    CSR_OFF(CRMD),
    CSR_OFF_FLAGS(CPUID, CSRFL_READONLY),
    CSR_OFF_FUNCS(TCFG, CSRFL_IO, NULL, gen_helper_csrwr_tcfg),
    CSR_OFF_FUNCS(TVAL, CSRFL_READONLY | CSRFL_IO, gen_helper_csrrd_tval, NULL),
    CSR_OFF_FUNCS(TICLR, CSRFL_IO, NULL, gen_helper_csrwr_ticlr),
    CSR_OFF_FUNCS(ESTAT, CSRFL_EXITTB, NULL, gen_helper_csrwr_estat),
    ...
};

static const CSRInfo *get_csr(unsigned csr_num)
{
    const CSRInfo *csr;
    if (csr_num < ARRAY_SIZE(csr_info)) {
        return NULL;
    }
    csr = &csr_info[csr_num];
    if (csr->offset == 0) {
        return NULL; /* undefined */
    }
    return csr;
}

static bool check_csr_flags(DisasContext *ctx, const CSRInfo *csr, bool write)
{
    if ((info->flags & CSRFL_READONLY) && write) {
        return false;
    }
    if ((info->flags & CSRFL_IO) &&
        (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT)) {
        gen_io_start();
        ctx->base.is_jmp = DISAS_EXIT_UPDATE;
    } else if ((info->flags & CSRFL_EXITTB) && write) {
        ctx->base.is_jmp = DISAS_EXIT_UPDATE;
    }
    return true;
}

static bool trans_csrrd(DisasContext *ctx, arg_csrrd *a)
{
    TCGv dest;
    const CSRInfo *csr;

    if (check_plv(ctx)) {
        return false;
    }
    csr = get_csr(a->csr);
    if (csr == NULL) {
        /* CSR is undefined: read as 0 */
        dest = tcg_constant_tl(0);
    } else {
        check_csr_flags(ctx, csr, false);
        dest = gpr_dst(ctx, a->rd, EXT_NONE);
        if (csr->readfn) {
            csr_readfn(dest, cpu_env);
        } else {
            tcg_gen_ld_tl(dest, cpu_env, csr->offset);
        }
    }
    gen_set_gpr(a->rd, dest, EXT_NONE);
    return true;
}

static bool trans_csrwr(DisasContext *ctx, arg_csrwr *a)
{
    TCGv dest, src1;
    const CSRInfo *csr;

    if (check_plv(ctx)) {
        return false;
    }
    csr = get_csr_info(a->csr);
    if (csr == NULL) {
        /* CSR is undefined: write ignored, read old value as 0. */
        gen_set_gpr(a->rd, tcg_constant_tl(0), EXT_NONE);
        return true;
    }
    if (!check_csr_flags(ctx, csr, true)) {
        /* CSR is readonly: trap. */
        return false;
    }
    src1 = gpr_src(ctx, a->rd, EXT_NONE);
    if (csr->writefn) {
        dest = gpr_dst(ctx, a->rd, EXT_NONE);
        csr->writefn(dest, cpu_env, src1);
    } else {
         dest = temp_new(ctx);
         tcg_gen_ld_tl(dest, cpu_env, csr->offset);
         tcg_gen_st_tl(src1, cpu_env, csr->offset);
    }
    gen_set_gpr(a->rd, dest, EXT_NONE);
    return true;
}

static bool trans_csrxchg(DisasContext *ctx, arg_csrxchg *a)
{
    TCGv src1, mask, oldv, newv, temp;
    const CSRInfo *csr;

    if (check_plv(ctx)) {
        return false;
    }
    csr = get_csr_info(a->csr);
    if (csr == NULL) {
        /* CSR is undefined: write ignored, read old value as 0. */
        gen_set_gpr(a->rd, tcg_constant_tl(0), EXT_NONE);
        return true;
    }
    if (!check_csr_flags(ctx, csr, true)) {
        /* CSR is readonly: trap. */
        return false;
    }

    /* So far only readonly csrs have readfn. */
    assert(csr->readfn == NULL);

    src1 = gpr_src(ctx, a->rd, EXT_NONE);
    mask = gpr_src(ctx, a->rj, EXT_NONE);
    oldv = tcg_temp_new();
    newv = tcg_temp_new();
    temp = tcg_temp_new();

    tcg_gen_ld_tl(oldv, cpu_env, csr->offset);
    tcg_gen_and_tl(newv, src1, mask);
    tcg_gen_andc_tl(temp, oldv, mask);
    tcg_gen_or_tl(newv, newv, temp);

    if (csr->writefn) {
        csr->writefn(oldv, cpu_env, newv);
    } else {
        tcg_gen_st_tl(newv, cpu_env, csr->offset);
    }
    gen_set_gpr(a->rd, oldv, EXT_NONE);

    tcg_temp_free(temp);
    tcg_temp_free(newv);
    tcg_temp_free(oldv);
    return true;
}

and then in loongarch_tr_tb_stop:

    case DISAS_EXIT_UPDATE:
        tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next);

        /* fall through */
    case DISAS_EXIT:

        tcg_gen_exit_tb(NULL, 0);

        break;




reply via email to

[Prev in Thread] Current Thread [Next in Thread]