loongarch queue

-----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQQNhkKjomWfgLCz0aQfewwSUazn0QUCZ5M4AwAKCRAfewwSUazn
 0aJAAP45/9qfbGSYiMCrBXpRFlyvtRN+GEXHEsERfk9Q1V+tQgEA/mMiUEcyc/xc
 Z1Z27cDoqUFRhPmxbd6/KyTGHzo2+As=
 =Zanw
 -----END PGP SIGNATURE-----

Merge tag 'pull-loongarch-20250124' of https://gitlab.com/bibo-mao/qemu into staging

loongarch queue

# -----BEGIN PGP SIGNATURE-----
#
# iHUEABYKAB0WIQQNhkKjomWfgLCz0aQfewwSUazn0QUCZ5M4AwAKCRAfewwSUazn
# 0aJAAP45/9qfbGSYiMCrBXpRFlyvtRN+GEXHEsERfk9Q1V+tQgEA/mMiUEcyc/xc
# Z1Z27cDoqUFRhPmxbd6/KyTGHzo2+As=
# =Zanw
# -----END PGP SIGNATURE-----
# gpg: Signature made Fri 24 Jan 2025 01:49:39 EST
# gpg:                using EDDSA key 0D8642A3A2659F80B0B3D1A41F7B0C1251ACE7D1
# gpg: Good signature from "bibo mao <maobibo@loongson.cn>" [unknown]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 7044 3A00 19C0 E97A 31C7  13C4 8E86 8FB7 A176 9D4C
#      Subkey fingerprint: 0D86 42A3 A265 9F80 B0B3  D1A4 1F7B 0C12 51AC E7D1

* tag 'pull-loongarch-20250124' of https://gitlab.com/bibo-mao/qemu:
  target/loongarch: Dump all generic CSR registers
  target/loongarch: Set unused flag with CSR registers
  target/loongarch: Add common source file for CSR register
  target/loongarch: Add common header file for CSR registers
  target/loongarch: Add generic csr function type
  target/loongarch: Remove static CSR function setting
  target/loongarch: Add dynamic function access with CSR register

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
Stefan Hajnoczi 2025-01-24 10:02:01 -05:00
commit 8f9cb50fe6
7 changed files with 294 additions and 139 deletions

View File

@ -19,7 +19,7 @@
#include "cpu.h" #include "cpu.h"
#include "internals.h" #include "internals.h"
#include "fpu/softfloat-helpers.h" #include "fpu/softfloat-helpers.h"
#include "cpu-csr.h" #include "csr.h"
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
#include "system/reset.h" #include "system/reset.h"
#endif #endif
@ -375,6 +375,33 @@ static int loongarch_cpu_mmu_index(CPUState *cs, bool ifetch)
return MMU_DA_IDX; return MMU_DA_IDX;
} }
static void loongarch_la464_init_csr(Object *obj)
{
#ifndef CONFIG_USER_ONLY
static bool initialized;
LoongArchCPU *cpu = LOONGARCH_CPU(obj);
CPULoongArchState *env = &cpu->env;
int i, num;
if (!initialized) {
initialized = true;
num = FIELD_EX64(env->CSR_PRCFG1, CSR_PRCFG1, SAVE_NUM);
for (i = num; i < 16; i++) {
set_csr_flag(LOONGARCH_CSR_SAVE(i), CSRFL_UNUSED);
}
set_csr_flag(LOONGARCH_CSR_IMPCTL1, CSRFL_UNUSED);
set_csr_flag(LOONGARCH_CSR_IMPCTL2, CSRFL_UNUSED);
set_csr_flag(LOONGARCH_CSR_MERRCTL, CSRFL_UNUSED);
set_csr_flag(LOONGARCH_CSR_MERRINFO1, CSRFL_UNUSED);
set_csr_flag(LOONGARCH_CSR_MERRINFO2, CSRFL_UNUSED);
set_csr_flag(LOONGARCH_CSR_MERRENTRY, CSRFL_UNUSED);
set_csr_flag(LOONGARCH_CSR_MERRERA, CSRFL_UNUSED);
set_csr_flag(LOONGARCH_CSR_MERRSAVE, CSRFL_UNUSED);
set_csr_flag(LOONGARCH_CSR_CTAG, CSRFL_UNUSED);
}
#endif
}
static void loongarch_la464_initfn(Object *obj) static void loongarch_la464_initfn(Object *obj)
{ {
LoongArchCPU *cpu = LOONGARCH_CPU(obj); LoongArchCPU *cpu = LOONGARCH_CPU(obj);
@ -470,6 +497,7 @@ static void loongarch_la464_initfn(Object *obj)
env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, STLB_WAYS, 7); env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, STLB_WAYS, 7);
env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, STLB_SETS, 8); env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, STLB_SETS, 8);
loongarch_la464_init_csr(obj);
loongarch_cpu_post_init(obj); loongarch_cpu_post_init(obj);
} }
@ -765,6 +793,54 @@ static ObjectClass *loongarch_cpu_class_by_name(const char *cpu_model)
return oc; return oc;
} }
static void loongarch_cpu_dump_csr(CPUState *cs, FILE *f)
{
#ifndef CONFIG_USER_ONLY
CPULoongArchState *env = cpu_env(cs);
CSRInfo *csr_info;
int64_t *addr;
int i, j, len, col = 0;
qemu_fprintf(f, "\n");
/* Dump all generic CSR register */
for (i = 0; i < LOONGARCH_CSR_DBG; i++) {
csr_info = get_csr(i);
if (!csr_info || (csr_info->flags & CSRFL_UNUSED)) {
if (i == (col + 3)) {
qemu_fprintf(f, "\n");
}
continue;
}
if ((i > (col + 3)) || (i == col)) {
col = i & ~3;
qemu_fprintf(f, " CSR%03d:", col);
}
addr = (void *)env + csr_info->offset;
qemu_fprintf(f, " %s ", csr_info->name);
len = strlen(csr_info->name);
for (; len < 6; len++) {
qemu_fprintf(f, " ");
}
qemu_fprintf(f, "%" PRIx64, *addr);
j = find_last_bit((void *)addr, BITS_PER_LONG) & (BITS_PER_LONG - 1);
len += j / 4 + 1;
for (; len < 22; len++) {
qemu_fprintf(f, " ");
}
if (i == (col + 3)) {
qemu_fprintf(f, "\n");
}
}
qemu_fprintf(f, "\n");
#endif
}
static void loongarch_cpu_dump_state(CPUState *cs, FILE *f, int flags) static void loongarch_cpu_dump_state(CPUState *cs, FILE *f, int flags)
{ {
CPULoongArchState *env = cpu_env(cs); CPULoongArchState *env = cpu_env(cs);
@ -784,22 +860,8 @@ static void loongarch_cpu_dump_state(CPUState *cs, FILE *f, int flags)
} }
} }
qemu_fprintf(f, "CRMD=%016" PRIx64 "\n", env->CSR_CRMD); /* csr */
qemu_fprintf(f, "PRMD=%016" PRIx64 "\n", env->CSR_PRMD); loongarch_cpu_dump_csr(cs, f);
qemu_fprintf(f, "EUEN=%016" PRIx64 "\n", env->CSR_EUEN);
qemu_fprintf(f, "ESTAT=%016" PRIx64 "\n", env->CSR_ESTAT);
qemu_fprintf(f, "ERA=%016" PRIx64 "\n", env->CSR_ERA);
qemu_fprintf(f, "BADV=%016" PRIx64 "\n", env->CSR_BADV);
qemu_fprintf(f, "BADI=%016" PRIx64 "\n", env->CSR_BADI);
qemu_fprintf(f, "EENTRY=%016" PRIx64 "\n", env->CSR_EENTRY);
qemu_fprintf(f, "PRCFG1=%016" PRIx64 ", PRCFG2=%016" PRIx64 ","
" PRCFG3=%016" PRIx64 "\n",
env->CSR_PRCFG1, env->CSR_PRCFG2, env->CSR_PRCFG3);
qemu_fprintf(f, "TLBRENTRY=%016" PRIx64 "\n", env->CSR_TLBRENTRY);
qemu_fprintf(f, "TLBRBADV=%016" PRIx64 "\n", env->CSR_TLBRBADV);
qemu_fprintf(f, "TLBRERA=%016" PRIx64 "\n", env->CSR_TLBRERA);
qemu_fprintf(f, "TCFG=%016" PRIx64 "\n", env->CSR_TCFG);
qemu_fprintf(f, "TVAL=%016" PRIx64 "\n", env->CSR_TVAL);
/* fpr */ /* fpr */
if (flags & CPU_DUMP_FPU) { if (flags & CPU_DUMP_FPU) {

129
target/loongarch/csr.c Normal file
View File

@ -0,0 +1,129 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (c) 2025 Loongson Technology Corporation Limited
*/
#include <stddef.h>
#include "qemu/osdep.h"
#include "cpu.h"
#include "csr.h"
#define CSR_OFF_FUNCS(NAME, FL, RD, WR) \
[LOONGARCH_CSR_##NAME] = { \
.name = (stringify(NAME)), \
.offset = offsetof(CPULoongArchState, CSR_##NAME), \
.flags = FL, .readfn = RD, .writefn = WR \
}
#define CSR_OFF_ARRAY(NAME, N) \
[LOONGARCH_CSR_##NAME(N)] = { \
.name = (stringify(NAME##N)), \
.offset = offsetof(CPULoongArchState, CSR_##NAME[N]), \
.flags = 0, .readfn = NULL, .writefn = NULL \
}
#define CSR_OFF_FLAGS(NAME, FL) CSR_OFF_FUNCS(NAME, FL, NULL, NULL)
#define CSR_OFF(NAME) CSR_OFF_FLAGS(NAME, 0)
static CSRInfo csr_info[] = {
CSR_OFF_FLAGS(CRMD, CSRFL_EXITTB),
CSR_OFF(PRMD),
CSR_OFF_FLAGS(EUEN, CSRFL_EXITTB),
CSR_OFF_FLAGS(MISC, CSRFL_READONLY),
CSR_OFF(ECFG),
CSR_OFF_FLAGS(ESTAT, CSRFL_EXITTB),
CSR_OFF(ERA),
CSR_OFF(BADV),
CSR_OFF_FLAGS(BADI, CSRFL_READONLY),
CSR_OFF(EENTRY),
CSR_OFF(TLBIDX),
CSR_OFF(TLBEHI),
CSR_OFF(TLBELO0),
CSR_OFF(TLBELO1),
CSR_OFF_FLAGS(ASID, CSRFL_EXITTB),
CSR_OFF(PGDL),
CSR_OFF(PGDH),
CSR_OFF_FLAGS(PGD, CSRFL_READONLY),
CSR_OFF(PWCL),
CSR_OFF(PWCH),
CSR_OFF(STLBPS),
CSR_OFF(RVACFG),
CSR_OFF_FLAGS(CPUID, CSRFL_READONLY),
CSR_OFF_FLAGS(PRCFG1, CSRFL_READONLY),
CSR_OFF_FLAGS(PRCFG2, CSRFL_READONLY),
CSR_OFF_FLAGS(PRCFG3, CSRFL_READONLY),
CSR_OFF_ARRAY(SAVE, 0),
CSR_OFF_ARRAY(SAVE, 1),
CSR_OFF_ARRAY(SAVE, 2),
CSR_OFF_ARRAY(SAVE, 3),
CSR_OFF_ARRAY(SAVE, 4),
CSR_OFF_ARRAY(SAVE, 5),
CSR_OFF_ARRAY(SAVE, 6),
CSR_OFF_ARRAY(SAVE, 7),
CSR_OFF_ARRAY(SAVE, 8),
CSR_OFF_ARRAY(SAVE, 9),
CSR_OFF_ARRAY(SAVE, 10),
CSR_OFF_ARRAY(SAVE, 11),
CSR_OFF_ARRAY(SAVE, 12),
CSR_OFF_ARRAY(SAVE, 13),
CSR_OFF_ARRAY(SAVE, 14),
CSR_OFF_ARRAY(SAVE, 15),
CSR_OFF(TID),
CSR_OFF_FLAGS(TCFG, CSRFL_IO),
CSR_OFF_FLAGS(TVAL, CSRFL_READONLY | CSRFL_IO),
CSR_OFF(CNTC),
CSR_OFF_FLAGS(TICLR, CSRFL_IO),
CSR_OFF(LLBCTL),
CSR_OFF(IMPCTL1),
CSR_OFF(IMPCTL2),
CSR_OFF(TLBRENTRY),
CSR_OFF(TLBRBADV),
CSR_OFF(TLBRERA),
CSR_OFF(TLBRSAVE),
CSR_OFF(TLBRELO0),
CSR_OFF(TLBRELO1),
CSR_OFF(TLBREHI),
CSR_OFF(TLBRPRMD),
CSR_OFF(MERRCTL),
CSR_OFF(MERRINFO1),
CSR_OFF(MERRINFO2),
CSR_OFF(MERRENTRY),
CSR_OFF(MERRERA),
CSR_OFF(MERRSAVE),
CSR_OFF(CTAG),
CSR_OFF_ARRAY(DMW, 0),
CSR_OFF_ARRAY(DMW, 1),
CSR_OFF_ARRAY(DMW, 2),
CSR_OFF_ARRAY(DMW, 3),
CSR_OFF(DBG),
CSR_OFF(DERA),
CSR_OFF(DSAVE),
};
CSRInfo *get_csr(unsigned int csr_num)
{
CSRInfo *csr;
if (csr_num >= ARRAY_SIZE(csr_info)) {
return NULL;
}
csr = &csr_info[csr_num];
if (csr->offset == 0) {
return NULL;
}
return csr;
}
bool set_csr_flag(unsigned int csr_num, int flag)
{
CSRInfo *csr;
csr = get_csr(csr_num);
if (!csr) {
return false;
}
csr->flags |= flag;
return true;
}

29
target/loongarch/csr.h Normal file
View File

@ -0,0 +1,29 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (c) 2025 Loongson Technology Corporation Limited
*/
#ifndef TARGET_LOONGARCH_CSR_H
#define TARGET_LOONGARCH_CSR_H
#include "cpu-csr.h"
typedef void (*GenCSRFunc)(void);
enum {
CSRFL_READONLY = (1 << 0),
CSRFL_EXITTB = (1 << 1),
CSRFL_IO = (1 << 2),
CSRFL_UNUSED = (1 << 3),
};
typedef struct {
const char *name;
int offset;
int flags;
GenCSRFunc readfn;
GenCSRFunc writefn;
} CSRInfo;
CSRInfo *get_csr(unsigned int csr_num);
bool set_csr_flag(unsigned int csr_num, int flag);
#endif /* TARGET_LOONGARCH_CSR_H */

View File

@ -10,6 +10,7 @@ loongarch_system_ss = ss.source_set()
loongarch_system_ss.add(files( loongarch_system_ss.add(files(
'arch_dump.c', 'arch_dump.c',
'cpu_helper.c', 'cpu_helper.c',
'csr.c',
'loongarch-qmp-cmds.c', 'loongarch-qmp-cmds.c',
'machine.c', 'machine.c',
)) ))

View File

@ -5,7 +5,7 @@
* LoongArch translation routines for the privileged instructions. * LoongArch translation routines for the privileged instructions.
*/ */
#include "cpu-csr.h" #include "csr.h"
#ifdef CONFIG_USER_ONLY #ifdef CONFIG_USER_ONLY
@ -45,112 +45,6 @@ GEN_FALSE_TRANS(idle)
typedef void (*GenCSRRead)(TCGv dest, TCGv_ptr env); typedef void (*GenCSRRead)(TCGv dest, TCGv_ptr env);
typedef void (*GenCSRWrite)(TCGv dest, TCGv_ptr env, TCGv src); 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_ARRAY(NAME, N) \
[LOONGARCH_CSR_##NAME(N)] = { \
.offset = offsetof(CPULoongArchState, CSR_##NAME[N]), \
.flags = 0, .readfn = NULL, .writefn = NULL \
}
#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_FLAGS(CRMD, CSRFL_EXITTB),
CSR_OFF(PRMD),
CSR_OFF_FLAGS(EUEN, CSRFL_EXITTB),
CSR_OFF_FLAGS(MISC, CSRFL_READONLY),
CSR_OFF(ECFG),
CSR_OFF_FUNCS(ESTAT, CSRFL_EXITTB, NULL, gen_helper_csrwr_estat),
CSR_OFF(ERA),
CSR_OFF(BADV),
CSR_OFF_FLAGS(BADI, CSRFL_READONLY),
CSR_OFF(EENTRY),
CSR_OFF(TLBIDX),
CSR_OFF(TLBEHI),
CSR_OFF(TLBELO0),
CSR_OFF(TLBELO1),
CSR_OFF_FUNCS(ASID, CSRFL_EXITTB, NULL, gen_helper_csrwr_asid),
CSR_OFF(PGDL),
CSR_OFF(PGDH),
CSR_OFF_FUNCS(PGD, CSRFL_READONLY, gen_helper_csrrd_pgd, NULL),
CSR_OFF_FUNCS(PWCL, 0, NULL, gen_helper_csrwr_pwcl),
CSR_OFF(PWCH),
CSR_OFF(STLBPS),
CSR_OFF(RVACFG),
CSR_OFF_FUNCS(CPUID, CSRFL_READONLY, gen_helper_csrrd_cpuid, NULL),
CSR_OFF_FLAGS(PRCFG1, CSRFL_READONLY),
CSR_OFF_FLAGS(PRCFG2, CSRFL_READONLY),
CSR_OFF_FLAGS(PRCFG3, CSRFL_READONLY),
CSR_OFF_ARRAY(SAVE, 0),
CSR_OFF_ARRAY(SAVE, 1),
CSR_OFF_ARRAY(SAVE, 2),
CSR_OFF_ARRAY(SAVE, 3),
CSR_OFF_ARRAY(SAVE, 4),
CSR_OFF_ARRAY(SAVE, 5),
CSR_OFF_ARRAY(SAVE, 6),
CSR_OFF_ARRAY(SAVE, 7),
CSR_OFF_ARRAY(SAVE, 8),
CSR_OFF_ARRAY(SAVE, 9),
CSR_OFF_ARRAY(SAVE, 10),
CSR_OFF_ARRAY(SAVE, 11),
CSR_OFF_ARRAY(SAVE, 12),
CSR_OFF_ARRAY(SAVE, 13),
CSR_OFF_ARRAY(SAVE, 14),
CSR_OFF_ARRAY(SAVE, 15),
CSR_OFF(TID),
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(CNTC),
CSR_OFF_FUNCS(TICLR, CSRFL_IO, NULL, gen_helper_csrwr_ticlr),
CSR_OFF(LLBCTL),
CSR_OFF(IMPCTL1),
CSR_OFF(IMPCTL2),
CSR_OFF(TLBRENTRY),
CSR_OFF(TLBRBADV),
CSR_OFF(TLBRERA),
CSR_OFF(TLBRSAVE),
CSR_OFF(TLBRELO0),
CSR_OFF(TLBRELO1),
CSR_OFF(TLBREHI),
CSR_OFF(TLBRPRMD),
CSR_OFF(MERRCTL),
CSR_OFF(MERRINFO1),
CSR_OFF(MERRINFO2),
CSR_OFF(MERRENTRY),
CSR_OFF(MERRERA),
CSR_OFF(MERRSAVE),
CSR_OFF(CTAG),
CSR_OFF_ARRAY(DMW, 0),
CSR_OFF_ARRAY(DMW, 1),
CSR_OFF_ARRAY(DMW, 2),
CSR_OFF_ARRAY(DMW, 3),
CSR_OFF(DBG),
CSR_OFF(DERA),
CSR_OFF(DSAVE),
};
static bool check_plv(DisasContext *ctx) static bool check_plv(DisasContext *ctx)
{ {
if (ctx->plv == MMU_PLV_USER) { if (ctx->plv == MMU_PLV_USER) {
@ -160,19 +54,36 @@ static bool check_plv(DisasContext *ctx)
return false; return false;
} }
static const CSRInfo *get_csr(unsigned csr_num) static bool set_csr_trans_func(unsigned int csr_num, GenCSRRead readfn,
GenCSRWrite writefn)
{ {
const CSRInfo *csr; CSRInfo *csr;
if (csr_num >= ARRAY_SIZE(csr_info)) { csr = get_csr(csr_num);
return NULL; if (!csr) {
return false;
} }
csr = &csr_info[csr_num];
if (csr->offset == 0) { csr->readfn = (GenCSRFunc)readfn;
return NULL; csr->writefn = (GenCSRFunc)writefn;
return true;
} }
return csr;
#define SET_CSR_FUNC(NAME, read, write) \
set_csr_trans_func(LOONGARCH_CSR_##NAME, read, write)
void loongarch_csr_translate_init(void)
{
SET_CSR_FUNC(ESTAT, NULL, gen_helper_csrwr_estat);
SET_CSR_FUNC(ASID, NULL, gen_helper_csrwr_asid);
SET_CSR_FUNC(PGD, gen_helper_csrrd_pgd, NULL);
SET_CSR_FUNC(PWCL, NULL, gen_helper_csrwr_pwcl);
SET_CSR_FUNC(CPUID, gen_helper_csrrd_cpuid, NULL);
SET_CSR_FUNC(TCFG, NULL, gen_helper_csrwr_tcfg);
SET_CSR_FUNC(TVAL, gen_helper_csrrd_tval, NULL);
SET_CSR_FUNC(TICLR, NULL, gen_helper_csrwr_ticlr);
} }
#undef SET_CSR_FUNC
static bool check_csr_flags(DisasContext *ctx, const CSRInfo *csr, bool write) static bool check_csr_flags(DisasContext *ctx, const CSRInfo *csr, bool write)
{ {
@ -191,6 +102,7 @@ static bool trans_csrrd(DisasContext *ctx, arg_csrrd *a)
{ {
TCGv dest; TCGv dest;
const CSRInfo *csr; const CSRInfo *csr;
GenCSRRead readfn;
if (check_plv(ctx)) { if (check_plv(ctx)) {
return false; return false;
@ -202,8 +114,9 @@ static bool trans_csrrd(DisasContext *ctx, arg_csrrd *a)
} else { } else {
check_csr_flags(ctx, csr, false); check_csr_flags(ctx, csr, false);
dest = gpr_dst(ctx, a->rd, EXT_NONE); dest = gpr_dst(ctx, a->rd, EXT_NONE);
if (csr->readfn) { readfn = (GenCSRRead)csr->readfn;
csr->readfn(dest, tcg_env); if (readfn) {
readfn(dest, tcg_env);
} else { } else {
tcg_gen_ld_tl(dest, tcg_env, csr->offset); tcg_gen_ld_tl(dest, tcg_env, csr->offset);
} }
@ -216,6 +129,7 @@ static bool trans_csrwr(DisasContext *ctx, arg_csrwr *a)
{ {
TCGv dest, src1; TCGv dest, src1;
const CSRInfo *csr; const CSRInfo *csr;
GenCSRWrite writefn;
if (check_plv(ctx)) { if (check_plv(ctx)) {
return false; return false;
@ -231,9 +145,10 @@ static bool trans_csrwr(DisasContext *ctx, arg_csrwr *a)
return false; return false;
} }
src1 = gpr_src(ctx, a->rd, EXT_NONE); src1 = gpr_src(ctx, a->rd, EXT_NONE);
if (csr->writefn) { writefn = (GenCSRWrite)csr->writefn;
if (writefn) {
dest = gpr_dst(ctx, a->rd, EXT_NONE); dest = gpr_dst(ctx, a->rd, EXT_NONE);
csr->writefn(dest, tcg_env, src1); writefn(dest, tcg_env, src1);
} else { } else {
dest = tcg_temp_new(); dest = tcg_temp_new();
tcg_gen_ld_tl(dest, tcg_env, csr->offset); tcg_gen_ld_tl(dest, tcg_env, csr->offset);
@ -247,6 +162,7 @@ static bool trans_csrxchg(DisasContext *ctx, arg_csrxchg *a)
{ {
TCGv src1, mask, oldv, newv, temp; TCGv src1, mask, oldv, newv, temp;
const CSRInfo *csr; const CSRInfo *csr;
GenCSRWrite writefn;
if (check_plv(ctx)) { if (check_plv(ctx)) {
return false; return false;
@ -277,8 +193,9 @@ static bool trans_csrxchg(DisasContext *ctx, arg_csrxchg *a)
tcg_gen_andc_tl(temp, oldv, mask); tcg_gen_andc_tl(temp, oldv, mask);
tcg_gen_or_tl(newv, newv, temp); tcg_gen_or_tl(newv, newv, temp);
if (csr->writefn) { writefn = (GenCSRWrite)csr->writefn;
csr->writefn(oldv, tcg_env, newv); if (writefn) {
writefn(oldv, tcg_env, newv);
} else { } else {
tcg_gen_st_tl(newv, tcg_env, csr->offset); tcg_gen_st_tl(newv, tcg_env, csr->offset);
} }

View File

@ -0,0 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* QEMU LoongArch TCG interface
*
* Copyright (c) 2025 Loongson Technology Corporation Limited
*/
#ifndef TARGET_LOONGARCH_TCG_LOONGARCH_H
#define TARGET_LOONGARCH_TCG_LOONGARCH_H
void loongarch_csr_translate_init(void);
#endif /* TARGET_LOONGARCH_TCG_LOONGARCH_H */

View File

@ -16,6 +16,7 @@
#include "exec/log.h" #include "exec/log.h"
#include "qemu/qemu-print.h" #include "qemu/qemu-print.h"
#include "fpu/softfloat.h" #include "fpu/softfloat.h"
#include "tcg_loongarch.h"
#include "translate.h" #include "translate.h"
#include "internals.h" #include "internals.h"
#include "vec.h" #include "vec.h"
@ -358,4 +359,8 @@ void loongarch_translate_init(void)
offsetof(CPULoongArchState, lladdr), "lladdr"); offsetof(CPULoongArchState, lladdr), "lladdr");
cpu_llval = tcg_global_mem_new(tcg_env, cpu_llval = tcg_global_mem_new(tcg_env,
offsetof(CPULoongArchState, llval), "llval"); offsetof(CPULoongArchState, llval), "llval");
#ifndef CONFIG_USER_ONLY
loongarch_csr_translate_init();
#endif
} }