[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH v1 25/43] target/loongarch: Add LoongArch CSR instruction
From: |
Richard Henderson |
Subject: |
Re: [PATCH v1 25/43] target/loongarch: Add LoongArch CSR instruction |
Date: |
Fri, 15 Apr 2022 18:04:16 -0700 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.7.0 |
On 4/15/22 02:40, Xiaojuan Yang wrote:
+int cpu_csr_offset(unsigned csr_num);
...
+static const uint64_t csr_offsets[] = {
There's no reason for this array to be uint64_t.
It really should match the function.
+target_ulong helper_csrwr_estat(CPULoongArchState *env, target_ulong val)
+{
+ int64_t old_v = env->CSR_ESTAT;
+
+ /* Only IS[1:0] can be written */
+ env->CSR_ESTAT = FIELD_DP64(env->CSR_ESTAT, CSR_ESTAT, IS, val & 0x3);
+
+ return old_v;
+}
This is incorrect. You're writing to all 13 bits of ESTAT.IS with the low 2 bits of val
-- i.e. clearing bits [12:2].
You want to use: env->CSR_ESTAT = deposit64(env->CSR_ESTAT, 0, 2, val);
+target_ulong helper_csrwr_asid(CPULoongArchState *env, target_ulong val)
+{
+ int64_t old_v = env->CSR_ASID;
+
+ /* Only ASID filed of CSR_ASID can be written */
+ env->CSR_ASID = FIELD_DP64(env->CSR_ASID, CSR_ASID, ASID,
+ val & R_CSR_ASID_ASID_MASK);
You do not need to mask the 4th argument of FIELD_DP64 -- that happens as part of the
deposit operation.
+ if (old_v != val) {
+ tlb_flush(env_cpu(env));
+ }
You shouldn't be comparing val to old_v, but old_v to the updated CSR_ASID.
+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.
+static void output_r_csr(DisasContext *ctx, arg_r_csr *a,
+ const char *mnemonic)
+{
+ output(ctx, mnemonic, "r%d, %d", a->rd, a->csr);
+}
+
+static void output_rr_csr(DisasContext *ctx, arg_rr_csr *a,
+ const char *mnemonic)
+{
+ output(ctx, mnemonic, "r%d, r%d, %d", a->rd, a->rj, a->csr);
+}
While this is fine, it would be nicer to print the name of CSR, when valid.
+static void gen_disas_exit(DisasContext *ctx)
+{
+ tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next + 4);
+ ctx->base.is_jmp = DISAS_EXIT;
+}
Why this function, and not simply place the movi in loongarch_tr_tb_stop too?
Or even just put the tcg_gen_exit_tb() here, and set DISAS_NORETURN.
I would say: one way or the other but not this mix...
+static bool trans_csrrd(DisasContext *ctx, arg_csrrd *a)
+{
+ TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE);
+
+ if (check_plv(ctx)) {
+ return false;
+ }
+
+ unsigned csr_offset = cpu_csr_offset(a->csr);
This is incorrect -- csr_offset must be signed, 'int', to match cpu_csr_offset and the
single negative value that exists within (CPUID).
+static bool trans_csrwr(DisasContext *ctx, arg_csrwr *a)
+{
+ TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE);
+ TCGv src1 = gpr_src(ctx, a->rd, EXT_NONE);
+
+ if (check_plv(ctx) || ro_csr(a->csr)) {
+ return false;
+ }
+
+ unsigned csr_offset = cpu_csr_offset(a->csr);
Again, 'int'.
+ if (csr_offset == 0) {
+ /* CSR is undefined: write ignored. */
+ return true;
+ }
+
+ switch (a->csr) {
+ case LOONGARCH_CSR_ESTAT:
+ gen_helper_csrwr_estat(dest, cpu_env, src1);
+ break;
+ case LOONGARCH_CSR_ASID:
+ gen_helper_csrwr_asid(dest, cpu_env, src1);
+ gen_disas_exit(ctx);
+ break;
+ case LOONGARCH_CSR_TCFG:
+ gen_helper_csrwr_tcfg(dest, cpu_env, src1);
+ break;
+ case LOONGARCH_CSR_TICLR:
+ gen_helper_csrwr_ticlr(dest, cpu_env, src1);
+ break;
+ default:
+ {
+ TCGv temp = tcg_temp_new();
+ tcg_gen_ld_tl(temp, cpu_env, csr_offset);
+ tcg_gen_st_tl(src1, cpu_env, csr_offset);
+ tcg_gen_mov_tl(dest, temp);
+ tcg_temp_free(temp);
+
+ /* Cpu state may be changed, need exit */
+ if ((a->csr == LOONGARCH_CSR_CRMD) ||
+ (a->csr == LOONGARCH_CSR_EUEN)) {
+ gen_disas_exit(ctx);
+ }
+ }
+ }
I said before that you needed to split out the body of this function for re-use
by csrxchg.
+ tcg_gen_not_tl(t1, mask);
+ tcg_gen_and_tl(t1, old_val, t1);
This is tcg_gen_andc_t1 (t1, old_val, mask).
+ 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.
+
+ if ((a->csr == LOONGARCH_CSR_ASID) || (a->csr == LOONGARCH_CSR_CRMD) ||
+ (a->csr == LOONGARCH_CSR_EUEN)) {
+ gen_disas_exit(ctx);
+ }
Note that this list does not match the list in trans_csrwr. This is *exactly* why I said
that you should split out a function for use between csrwr and csrxchg.
r~
- [PATCH v1 16/43] target/loongarch: Add disassembler, (continued)
- [PATCH v1 16/43] target/loongarch: Add disassembler, Xiaojuan Yang, 2022/04/15
- [PATCH v1 21/43] target/loongarch: Implement qmp_query_cpu_definitions(), Xiaojuan Yang, 2022/04/15
- [PATCH v1 36/43] hw/loongarch: Add irq hierarchy for the system, Xiaojuan Yang, 2022/04/15
- [PATCH v1 12/43] target/loongarch: Add floating point conversion instruction translation, Xiaojuan Yang, 2022/04/15
- [PATCH v1 28/43] target/loongarch: Add other core instructions support, Xiaojuan Yang, 2022/04/15
- [PATCH v1 42/43] tests/tcg/loongarch64: Add hello/memory test in loongarch64 system, Xiaojuan Yang, 2022/04/15
- [PATCH v1 25/43] target/loongarch: Add LoongArch CSR instruction, Xiaojuan Yang, 2022/04/15
[PATCH v1 40/43] hw/loongarch: Add LoongArch boot code and load elf function., Xiaojuan Yang, 2022/04/15
[PATCH v1 38/43] hw/loongarch: Add some devices support for 3A5000., Xiaojuan Yang, 2022/04/15
[PATCH v1 34/43] hw/intc: Add LoongArch ls7a msi interrupt controller support(PCH-MSI), Xiaojuan Yang, 2022/04/15