On 4/19/22 00:33, yangxiaojuan wrote:
On 2022/4/16 上午9:04, Richard Henderson wrote:
On 4/15/22 02:40, Xiaojuan Yang wrote:
...
+void helper_csr_update(CPULoongArchState *env, target_ulong new_val,
+ target_ulong csr_offset)
+{
+ uint64_t *csr = (void *)env + csr_offset;
+
+ *csr = new_val;
+}
This function should not exist
...
+ switch (a->csr) {
+ case LOONGARCH_CSR_ESTAT:
+ gen_helper_csrwr_estat(dest, cpu_env, new_val);
+ break;
+ case LOONGARCH_CSR_ASID:
+ gen_helper_csrwr_asid(dest, cpu_env, new_val);
+ break;
+ case LOONGARCH_CSR_TCFG:
+ gen_helper_csrwr_tcfg(dest, cpu_env, new_val);
+ break;
+ case LOONGARCH_CSR_TICLR:
+ gen_helper_csrwr_ticlr(dest, cpu_env, new_val);
+ break;
+ default:
+ tcg_gen_mov_tl(dest, old_val);
+ }
+
+ gen_helper_csr_update(cpu_env, new_val, tcg_constant_tl(csr_offset));
Note that helper_csr_update is nothing more than the store to csr_offset.
On trans_csrxchg() , I am don't know how to use a TCGv value 'new_val 'to update an
uint64_t value "CSR_XXX", So I use helper_csr_update(),
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.
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;