Skip to content

Commit

Permalink
target/mips: Implement Loongson CSR instructions
Browse files Browse the repository at this point in the history
Loongson introduced CSR instructions since 3A4000, which looks
similar to IOCSR and CPUCFG instructions we seen in LoongArch.

Unfortunately we don't have much document about those instructions,
bit fields of CPUCFG instructions and IOCSR registers can be found
at 3A4000's user manual, while instruction encodings can be found
at arch/mips/include/asm/mach-loongson64/loongson_regs.h from
Linux Kernel.

Our predefined CPUCFG bits are differ from actual 3A4000, since
we can't emulate all CPUCFG features present in 3A4000 for now,
we just enable bits for what we have in TCG.

Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
Message-Id: <20230521214832.20145-2-jiaxun.yang@flygoat.com>
[JY:  Fixed typo in ase_lcsr_available(),
      retrict GEN_FALSE_TRANS]
[PMD: Fix meson's mips_softmmu_ss -> mips_system_ss,
      restrict AddressSpace/MemoryRegion to SysEmu]
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
  • Loading branch information
FlyGoat authored and philmd committed Jul 10, 2023
1 parent b263688 commit 03afdc2
Show file tree
Hide file tree
Showing 14 changed files with 238 additions and 0 deletions.
9 changes: 9 additions & 0 deletions target/mips/cpu-defs.c.inc
Original file line number Diff line number Diff line change
Expand Up @@ -895,6 +895,15 @@ const mips_def_t mips_defs[] =
.CP1_fcr31 = 0,
.CP1_fcr31_rw_bitmask = 0xFF83FFFF,
.MSAIR = (0x01 << MSAIR_ProcID) | (0x40 << MSAIR_Rev),
.lcsr_cpucfg1 = (1 << CPUCFG1_FP) | (2 << CPUCFG1_FPREV) |
(1 << CPUCFG1_MSA1) | (1 << CPUCFG1_LSLDR0) |
(1 << CPUCFG1_LSPERF) | (1 << CPUCFG1_LSPERFX) |
(1 << CPUCFG1_LSSYNCI) | (1 << CPUCFG1_LLEXC) |
(1 << CPUCFG1_SCRAND) | (1 << CPUCFG1_MUALP) |
(1 << CPUCFG1_KMUALEN) | (1 << CPUCFG1_ITLBT) |
(1 << CPUCFG1_SFBP) | (1 << CPUCFG1_CDMAP),
.lcsr_cpucfg2 = (1 << CPUCFG2_LEXT1) | (1 << CPUCFG2_LCSRP) |
(1 << CPUCFG2_LDISBLIKELY),
.SEGBITS = 48,
.PABITS = 48,
.insn_flags = CPU_MIPS64R2 | INSN_LOONGSON3A |
Expand Down
10 changes: 10 additions & 0 deletions target/mips/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,8 @@ static void mips_cpu_reset_hold(Object *obj)
env->CP0_PageGrain_rw_bitmask = env->cpu_model->CP0_PageGrain_rw_bitmask;
env->CP0_PageGrain = env->cpu_model->CP0_PageGrain;
env->CP0_EBaseWG_rw_bitmask = env->cpu_model->CP0_EBaseWG_rw_bitmask;
env->lcsr_cpucfg1 = env->cpu_model->lcsr_cpucfg1;
env->lcsr_cpucfg2 = env->cpu_model->lcsr_cpucfg2;
env->active_fpu.fcr0 = env->cpu_model->CP1_fcr0;
env->active_fpu.fcr31_rw_bitmask = env->cpu_model->CP1_fcr31_rw_bitmask;
env->active_fpu.fcr31 = env->cpu_model->CP1_fcr31;
Expand Down Expand Up @@ -507,6 +509,14 @@ static void mips_cpu_initfn(Object *obj)
cpu->count_div = clock_new(OBJECT(obj), "clk-div-count");
env->count_clock = clock_new(OBJECT(obj), "clk-count");
env->cpu_model = mcc->cpu_def;
#ifndef CONFIG_USER_ONLY
if (mcc->cpu_def->lcsr_cpucfg2 & (1 << CPUCFG2_LCSRP)) {
memory_region_init_io(&env->iocsr.mr, OBJECT(cpu), NULL,
env, "iocsr", UINT64_MAX);
address_space_init(&env->iocsr.as,
&env->iocsr.mr, "IOCSR");
}
#endif
}

static char *mips_cpu_type_name(const char *cpu_model)
Expand Down
42 changes: 42 additions & 0 deletions target/mips/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@

#include "cpu-qom.h"
#include "exec/cpu-defs.h"
#ifndef CONFIG_USER_ONLY
#include "exec/memory.h"
#endif
#include "fpu/softfloat-types.h"
#include "hw/clock.h"
#include "mips-defs.h"
Expand Down Expand Up @@ -1068,6 +1071,33 @@ typedef struct CPUArchState {
*/
int32_t CP0_DESAVE;
target_ulong CP0_KScratch[MIPS_KSCRATCH_NUM];
/*
* Loongson CSR CPUCFG registers
*/
uint32_t lcsr_cpucfg1;
#define CPUCFG1_FP 0
#define CPUCFG1_FPREV 1
#define CPUCFG1_MMI 4
#define CPUCFG1_MSA1 5
#define CPUCFG1_MSA2 6
#define CPUCFG1_LSLDR0 16
#define CPUCFG1_LSPERF 17
#define CPUCFG1_LSPERFX 18
#define CPUCFG1_LSSYNCI 19
#define CPUCFG1_LLEXC 20
#define CPUCFG1_SCRAND 21
#define CPUCFG1_MUALP 25
#define CPUCFG1_KMUALEN 26
#define CPUCFG1_ITLBT 27
#define CPUCFG1_SFBP 29
#define CPUCFG1_CDMAP 30
uint32_t lcsr_cpucfg2;
#define CPUCFG2_LEXT1 0
#define CPUCFG2_LEXT2 1
#define CPUCFG2_LEXT3 2
#define CPUCFG2_LSPW 3
#define CPUCFG2_LCSRP 27
#define CPUCFG2_LDISBLIKELY 28

/* We waste some space so we can handle shadow registers like TCs. */
TCState tcs[MIPS_SHADOW_SET_MAX];
Expand Down Expand Up @@ -1156,6 +1186,12 @@ typedef struct CPUArchState {
void *irq[8];
struct MIPSITUState *itu;
MemoryRegion *itc_tag; /* ITC Configuration Tags */

/* Loongson IOCSR memory */
struct {
AddressSpace as;
MemoryRegion mr;
} iocsr;
#endif

const mips_def_t *cpu_model;
Expand Down Expand Up @@ -1281,6 +1317,12 @@ static inline bool ase_msa_available(CPUMIPSState *env)
return env->CP0_Config3 & (1 << CP0C3_MSAP);
}

/* Check presence of Loongson CSR instructions */
static inline bool ase_lcsr_available(CPUMIPSState *env)
{
return env->lcsr_cpucfg2 & (1 << CPUCFG2_LCSRP);
}

/* Check presence of multi-threading ASE implementation */
static inline bool ase_mt_available(CPUMIPSState *env)
{
Expand Down
4 changes: 4 additions & 0 deletions target/mips/helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,10 @@ DEF_HELPER_1(rdhwr_xnp, tl, env)
DEF_HELPER_2(pmon, void, env, int)
DEF_HELPER_1(wait, void, env)

#ifdef TARGET_MIPS64
DEF_HELPER_FLAGS_2(lcsr_cpucfg, TCG_CALL_NO_RWG_SE, tl, env, tl)
#endif

/* Loongson multimedia functions. */
DEF_HELPER_FLAGS_2(paddsh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(paddush, TCG_CALL_NO_RWG_SE, i64, i64, i64)
Expand Down
2 changes: 2 additions & 0 deletions target/mips/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ struct mips_def_t {
int32_t CP0_PageGrain_rw_bitmask;
int32_t CP0_PageGrain;
target_ulong CP0_EBaseWG_rw_bitmask;
uint32_t lcsr_cpucfg1;
uint32_t lcsr_cpucfg2;
uint64_t insn_flags;
enum mips_mmu_types mmu_type;
int32_t SAARP;
Expand Down
17 changes: 17 additions & 0 deletions target/mips/tcg/lcsr.decode
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Loongson CSR instructions
#
# Copyright (C) 2023 Jiaxun Yang <jiaxun.yang@flygoat.com>
#
# SPDX-License-Identifier: LGPL-2.1-or-later
#

&r rs rt rd sa

@rs_rd ...... rs:5 ..... rd:5 ..... ...... &r rt=0 sa=0

CPUCFG 110010 ..... 01000 ..... 00100 011000 @rs_rd

RDCSR 110010 ..... 00000 ..... 00100 011000 @rs_rd
WRCSR 110010 ..... 00001 ..... 00100 011000 @rs_rd
DRDCSR 110010 ..... 00010 ..... 00100 011000 @rs_rd
DWRCSR 110010 ..... 00011 ..... 00100 011000 @rs_rd
75 changes: 75 additions & 0 deletions target/mips/tcg/lcsr_translate.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Loongson CSR instructions translation routines
*
* Copyright (c) 2023 Jiaxun Yang <jiaxun.yang@flygoat.com>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/

#include "qemu/osdep.h"
#include "cpu.h"
#include "tcg/tcg-op.h"
#include "tcg/tcg-op-gvec.h"
#include "exec/helper-gen.h"
#include "translate.h"

/* Include the auto-generated decoder. */
#include "decode-lcsr.c.inc"

static bool trans_CPUCFG(DisasContext *ctx, arg_CPUCFG *a)
{
TCGv dest = tcg_temp_new();
TCGv src1 = tcg_temp_new();

gen_load_gpr(src1, a->rs);
gen_helper_lcsr_cpucfg(dest, cpu_env, src1);
gen_store_gpr(dest, a->rd);

return true;
}

#ifndef CONFIG_USER_ONLY
static bool gen_rdcsr(DisasContext *ctx, arg_r *a,
void (*func)(TCGv, TCGv_ptr, TCGv))
{
TCGv dest = tcg_temp_new();
TCGv src1 = tcg_temp_new();

check_cp0_enabled(ctx);
gen_load_gpr(src1, a->rs);
func(dest, cpu_env, src1);
gen_store_gpr(dest, a->rd);

return true;
}

static bool gen_wrcsr(DisasContext *ctx, arg_r *a,
void (*func)(TCGv_ptr, TCGv, TCGv))
{
TCGv val = tcg_temp_new();
TCGv addr = tcg_temp_new();

check_cp0_enabled(ctx);
gen_load_gpr(addr, a->rs);
gen_load_gpr(val, a->rd);
func(cpu_env, addr, val);

return true;
}

TRANS(RDCSR, gen_rdcsr, gen_helper_lcsr_rdcsr)
TRANS(DRDCSR, gen_rdcsr, gen_helper_lcsr_drdcsr)
TRANS(WRCSR, gen_wrcsr, gen_helper_lcsr_wrcsr)
TRANS(DWRCSR, gen_wrcsr, gen_helper_lcsr_dwrcsr)
#else
#define GEN_FALSE_TRANS(name) \
static bool trans_##name(DisasContext *ctx, arg_##name * a) \
{ \
return false; \
}

GEN_FALSE_TRANS(RDCSR)
GEN_FALSE_TRANS(DRDCSR)
GEN_FALSE_TRANS(WRCSR)
GEN_FALSE_TRANS(DWRCSR)
#endif
2 changes: 2 additions & 0 deletions target/mips/tcg/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ gen = [
decodetree.process('tx79.decode', extra_args: '--static-decode=decode_tx79'),
decodetree.process('vr54xx.decode', extra_args: '--decode=decode_ext_vr54xx'),
decodetree.process('octeon.decode', extra_args: '--decode=decode_ext_octeon'),
decodetree.process('lcsr.decode', extra_args: '--decode=decode_ase_lcsr'),
]

mips_ss.add(gen)
Expand All @@ -26,6 +27,7 @@ mips_ss.add(files(
mips_ss.add(when: 'TARGET_MIPS64', if_true: files(
'tx79_translate.c',
'octeon_translate.c',
'lcsr_translate.c',
), if_false: files(
'mxu_translate.c',
))
Expand Down
16 changes: 16 additions & 0 deletions target/mips/tcg/op_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,22 @@ void helper_pmon(CPUMIPSState *env, int function)
}
}

#ifdef TARGET_MIPS64
target_ulong helper_lcsr_cpucfg(CPUMIPSState *env, target_ulong rs)
{
switch (rs) {
case 0:
return env->CP0_PRid;
case 1:
return env->lcsr_cpucfg1;
case 2:
return env->lcsr_cpucfg2;
default:
return 0;
}
}
#endif

#if !defined(CONFIG_USER_ONLY)

void mips_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
Expand Down
45 changes: 45 additions & 0 deletions target/mips/tcg/sysemu/lcsr_helper.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Loongson CSR instructions translation routines
*
* Copyright (c) 2023 Jiaxun Yang <jiaxun.yang@flygoat.com>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/

#include "qemu/osdep.h"
#include "qemu/main-loop.h"
#include "cpu.h"
#include "internal.h"
#include "qemu/host-utils.h"
#include "exec/helper-proto.h"
#include "exec/exec-all.h"
#include "exec/cpu_ldst.h"

#define GET_MEMTXATTRS(cas) \
((MemTxAttrs){.requester_id = env_cpu(cas)->cpu_index})

uint64_t helper_lcsr_rdcsr(CPUMIPSState *env, target_ulong r_addr)
{
return address_space_ldl(&env->iocsr.as, r_addr,
GET_MEMTXATTRS(env), NULL);
}

uint64_t helper_lcsr_drdcsr(CPUMIPSState *env, target_ulong r_addr)
{
return address_space_ldq(&env->iocsr.as, r_addr,
GET_MEMTXATTRS(env), NULL);
}

void helper_lcsr_wrcsr(CPUMIPSState *env, target_ulong w_addr,
target_ulong val)
{
address_space_stl(&env->iocsr.as, w_addr,
val, GET_MEMTXATTRS(env), NULL);
}

void helper_lcsr_dwrcsr(CPUMIPSState *env, target_ulong w_addr,
target_ulong val)
{
address_space_stq(&env->iocsr.as, w_addr,
val, GET_MEMTXATTRS(env), NULL);
}
4 changes: 4 additions & 0 deletions target/mips/tcg/sysemu/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,7 @@ mips_system_ss.add(files(
'special_helper.c',
'tlb_helper.c',
))

mips_system_ss.add(when: 'TARGET_MIPS64', if_true: files(
'lcsr_helper.c',
))
8 changes: 8 additions & 0 deletions target/mips/tcg/sysemu_helper.h.inc
Original file line number Diff line number Diff line change
Expand Up @@ -181,3 +181,11 @@ DEF_HELPER_1(eret, void, env)
DEF_HELPER_1(eretnc, void, env)
DEF_HELPER_1(deret, void, env)
DEF_HELPER_3(cache, void, env, tl, i32)

#ifdef TARGET_MIPS64
/* Longson CSR */
DEF_HELPER_2(lcsr_rdcsr, i64, env, tl)
DEF_HELPER_2(lcsr_drdcsr, i64, env, tl)
DEF_HELPER_3(lcsr_wrcsr, void, env, tl, tl)
DEF_HELPER_3(lcsr_dwrcsr, void, env, tl, tl)
#endif
3 changes: 3 additions & 0 deletions target/mips/tcg/translate.c
Original file line number Diff line number Diff line change
Expand Up @@ -15352,6 +15352,9 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx)
return;
}
#if defined(TARGET_MIPS64)
if (ase_lcsr_available(env) && decode_ase_lcsr(ctx, ctx->opcode)) {
return;
}
if (cpu_supports_isa(env, INSN_OCTEON) && decode_ext_octeon(ctx, ctx->opcode)) {
return;
}
Expand Down
1 change: 1 addition & 0 deletions target/mips/tcg/translate.h
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ bool decode_isa_rel6(DisasContext *ctx, uint32_t insn);
bool decode_ase_msa(DisasContext *ctx, uint32_t insn);
bool decode_ext_txx9(DisasContext *ctx, uint32_t insn);
#if defined(TARGET_MIPS64)
bool decode_ase_lcsr(DisasContext *ctx, uint32_t insn);
bool decode_ext_tx79(DisasContext *ctx, uint32_t insn);
bool decode_ext_octeon(DisasContext *ctx, uint32_t insn);
#endif
Expand Down

0 comments on commit 03afdc2

Please sign in to comment.