qemu/target/mips/tcg/translate.h
Jiaxun Yang 03afdc28b3 target/mips: Implement Loongson CSR instructions
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>
2023-07-10 23:33:37 +02:00

244 lines
7.9 KiB
C

/*
* MIPS translation routines.
*
* Copyright (c) 2004-2005 Jocelyn Mayer
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#ifndef TARGET_MIPS_TRANSLATE_H
#define TARGET_MIPS_TRANSLATE_H
#include "cpu.h"
#include "tcg/tcg-op.h"
#include "exec/translator.h"
#include "exec/helper-gen.h"
#include "qemu/log.h"
#define MIPS_DEBUG_DISAS 0
typedef struct DisasContext {
DisasContextBase base;
target_ulong saved_pc;
target_ulong page_start;
uint32_t opcode;
uint64_t insn_flags;
int32_t CP0_Config0;
int32_t CP0_Config1;
int32_t CP0_Config2;
int32_t CP0_Config3;
int32_t CP0_Config5;
/* Routine used to access memory */
int mem_idx;
MemOp default_tcg_memop_mask;
uint32_t hflags, saved_hflags;
target_ulong btarget;
bool ulri;
int kscrexist;
bool rxi;
int ie;
bool bi;
bool bp;
uint64_t PAMask;
bool mvh;
bool eva;
bool sc;
int CP0_LLAddr_shift;
bool ps;
bool vp;
bool cmgcr;
bool mrp;
bool nan2008;
bool abs2008;
bool saar;
bool mi;
int gi;
} DisasContext;
#define DISAS_STOP DISAS_TARGET_0
#define DISAS_EXIT DISAS_TARGET_1
#define DISAS_SEMIHOST DISAS_TARGET_2
/* MIPS major opcodes */
#define MASK_OP_MAJOR(op) (op & (0x3F << 26))
#define OPC_CP1 (0x11 << 26)
/* Coprocessor 1 (rs field) */
#define MASK_CP1(op) (MASK_OP_MAJOR(op) | (op & (0x1F << 21)))
/* Values for the fmt field in FP instructions */
enum {
/* 0 - 15 are reserved */
FMT_S = 16, /* single fp */
FMT_D = 17, /* double fp */
FMT_E = 18, /* extended fp */
FMT_Q = 19, /* quad fp */
FMT_W = 20, /* 32-bit fixed */
FMT_L = 21, /* 64-bit fixed */
FMT_PS = 22, /* paired single fp */
/* 23 - 31 are reserved */
};
enum {
OPC_MFC1 = (0x00 << 21) | OPC_CP1,
OPC_DMFC1 = (0x01 << 21) | OPC_CP1,
OPC_CFC1 = (0x02 << 21) | OPC_CP1,
OPC_MFHC1 = (0x03 << 21) | OPC_CP1,
OPC_MTC1 = (0x04 << 21) | OPC_CP1,
OPC_DMTC1 = (0x05 << 21) | OPC_CP1,
OPC_CTC1 = (0x06 << 21) | OPC_CP1,
OPC_MTHC1 = (0x07 << 21) | OPC_CP1,
OPC_BC1 = (0x08 << 21) | OPC_CP1, /* bc */
OPC_BC1ANY2 = (0x09 << 21) | OPC_CP1,
OPC_BC1ANY4 = (0x0A << 21) | OPC_CP1,
OPC_S_FMT = (FMT_S << 21) | OPC_CP1,
OPC_D_FMT = (FMT_D << 21) | OPC_CP1,
OPC_E_FMT = (FMT_E << 21) | OPC_CP1,
OPC_Q_FMT = (FMT_Q << 21) | OPC_CP1,
OPC_W_FMT = (FMT_W << 21) | OPC_CP1,
OPC_L_FMT = (FMT_L << 21) | OPC_CP1,
OPC_PS_FMT = (FMT_PS << 21) | OPC_CP1,
OPC_BC1EQZ = (0x09 << 21) | OPC_CP1,
OPC_BC1NEZ = (0x0D << 21) | OPC_CP1,
};
#define MASK_CP1_FUNC(op) (MASK_CP1(op) | (op & 0x3F))
#define MASK_BC1(op) (MASK_CP1(op) | (op & (0x3 << 16)))
enum {
OPC_BC1F = (0x00 << 16) | OPC_BC1,
OPC_BC1T = (0x01 << 16) | OPC_BC1,
OPC_BC1FL = (0x02 << 16) | OPC_BC1,
OPC_BC1TL = (0x03 << 16) | OPC_BC1,
};
enum {
OPC_BC1FANY2 = (0x00 << 16) | OPC_BC1ANY2,
OPC_BC1TANY2 = (0x01 << 16) | OPC_BC1ANY2,
};
enum {
OPC_BC1FANY4 = (0x00 << 16) | OPC_BC1ANY4,
OPC_BC1TANY4 = (0x01 << 16) | OPC_BC1ANY4,
};
#define gen_helper_0e1i(name, arg1, arg2) do { \
gen_helper_##name(cpu_env, arg1, tcg_constant_i32(arg2)); \
} while (0)
#define gen_helper_1e0i(name, ret, arg1) do { \
gen_helper_##name(ret, cpu_env, tcg_constant_i32(arg1)); \
} while (0)
#define gen_helper_0e2i(name, arg1, arg2, arg3) do { \
gen_helper_##name(cpu_env, arg1, arg2, tcg_constant_i32(arg3));\
} while (0)
void generate_exception(DisasContext *ctx, int excp);
void generate_exception_err(DisasContext *ctx, int excp, int err);
void generate_exception_end(DisasContext *ctx, int excp);
void generate_exception_break(DisasContext *ctx, int code);
void gen_reserved_instruction(DisasContext *ctx);
void check_insn(DisasContext *ctx, uint64_t flags);
void check_mips_64(DisasContext *ctx);
/**
* check_cp0_enabled:
* Return %true if CP0 is enabled, otherwise return %false
* and emit a 'coprocessor unusable' exception.
*/
bool check_cp0_enabled(DisasContext *ctx);
void check_cp1_enabled(DisasContext *ctx);
void check_cp1_64bitmode(DisasContext *ctx);
void check_cp1_registers(DisasContext *ctx, int regs);
void check_cop1x(DisasContext *ctx);
void gen_base_offset_addr(DisasContext *ctx, TCGv addr, int base, int offset);
void gen_move_low32(TCGv ret, TCGv_i64 arg);
void gen_move_high32(TCGv ret, TCGv_i64 arg);
void gen_load_gpr(TCGv t, int reg);
void gen_store_gpr(TCGv t, int reg);
#if defined(TARGET_MIPS64)
void gen_load_gpr_hi(TCGv_i64 t, int reg);
void gen_store_gpr_hi(TCGv_i64 t, int reg);
#endif /* TARGET_MIPS64 */
void gen_load_fpr32(DisasContext *ctx, TCGv_i32 t, int reg);
void gen_load_fpr64(DisasContext *ctx, TCGv_i64 t, int reg);
void gen_store_fpr32(DisasContext *ctx, TCGv_i32 t, int reg);
void gen_store_fpr64(DisasContext *ctx, TCGv_i64 t, int reg);
int get_fp_bit(int cc);
void gen_ldxs(DisasContext *ctx, int base, int index, int rd);
void gen_align(DisasContext *ctx, int wordsz, int rd, int rs, int rt, int bp);
void gen_addiupc(DisasContext *ctx, int rx, int imm,
int is_64_bit, int extended);
/*
* Address Computation and Large Constant Instructions
*/
void gen_op_addr_add(DisasContext *ctx, TCGv ret, TCGv arg0, TCGv arg1);
bool gen_lsa(DisasContext *ctx, int rd, int rt, int rs, int sa);
bool gen_dlsa(DisasContext *ctx, int rd, int rt, int rs, int sa);
void gen_rdhwr(DisasContext *ctx, int rt, int rd, int sel);
extern TCGv cpu_gpr[32], cpu_PC;
#if defined(TARGET_MIPS64)
extern TCGv_i64 cpu_gpr_hi[32];
#endif
extern TCGv cpu_HI[MIPS_DSP_ACC], cpu_LO[MIPS_DSP_ACC];
extern TCGv_i32 fpu_fcr0, fpu_fcr31;
extern TCGv_i64 fpu_f64[32];
extern TCGv bcond;
#define LOG_DISAS(...) \
do { \
if (MIPS_DEBUG_DISAS) { \
qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__); \
} \
} while (0)
#define MIPS_INVAL(op) \
do { \
if (MIPS_DEBUG_DISAS) { \
qemu_log_mask(CPU_LOG_TB_IN_ASM, \
TARGET_FMT_lx ": %08x Invalid %s %03x %03x %03x\n", \
ctx->base.pc_next, ctx->opcode, op, \
ctx->opcode >> 26, ctx->opcode & 0x3F, \
((ctx->opcode >> 16) & 0x1F)); \
} \
} while (0)
/* MSA */
void msa_translate_init(void);
/* MXU */
void mxu_translate_init(void);
bool decode_ase_mxu(DisasContext *ctx, uint32_t insn);
/* decodetree generated */
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
bool decode_ext_vr54xx(DisasContext *ctx, uint32_t insn);
/*
* Helpers for implementing sets of trans_* functions.
* Defer the implementation of NAME to FUNC, with optional extra arguments.
*/
#define TRANS(NAME, FUNC, ...) \
static bool trans_##NAME(DisasContext *ctx, arg_##NAME *a) \
{ return FUNC(ctx, a, __VA_ARGS__); }
static inline bool cpu_is_bigendian(DisasContext *ctx)
{
return extract32(ctx->CP0_Config0, CP0C0_BE, 1);
}
#endif