aboutsummaryrefslogtreecommitdiff
path: root/target
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2024-11-05 14:23:01 +0000
committerPeter Maydell <peter.maydell@linaro.org>2024-11-05 14:23:01 +0000
commit67194c7018b8b06a1c149757f596bb919c683725 (patch)
tree911935aab4ab1a75e6237f6546067b549552c3bb /target
parent9a7b0a8618b1293d589a631183e80791ad7bf552 (diff)
parenta144a3baa61e3fca1a7946685128c349dd92c76f (diff)
Merge tag 'mips-20241104' of https://github.com/philmd/qemu into staging
MIPS patches queue - Migrate missing CP0 TLB MemoryMapID register (Yongbok) - Enable MSA ASE for mips32r6-generic (Aleksandar) - Convert Loongson LEXT opcodes to decodetree (Philippe) - Introduce ase_3d_available and disas_mt_available helpers (Philippe) # -----BEGIN PGP SIGNATURE----- # # iQIzBAABCAAdFiEE+qvnXhKRciHc/Wuy4+MsLN6twN4FAmcopxgACgkQ4+MsLN6t # wN4DzQ//UPDSvcwCj6QIZ2TR2oKG5JIVRYrep7aUb+LdK1uus8P2G9REMnr1X/uC # 817aiUC6fK/PJEGAo6dTCKrPnMz71YAHM2259jreQXVZtCzOEzU9Fg9RHBCrbzxP # +kL+Sjzvnw3Kp0jVB1sgNn8PhKCkIVg9Go6tr4sXyTjINzsNbk78H6w3O4YlFOSX # dbQLWDpFQQRvliiSJR5erQyELs1tVJt+76aab9mM7uWvSbpX/6O80bJ607fUFG8J # t07c5u6aOU1MaZrGE5KO6G7BQwqYE/O3lGAd1akj8UMQNxJY8lrS+4bxH9+vjJTF # ojRdTRGa2cXC1wxiifFphUNfJe2fH+Wvjtdpgnu3vdp17J0wbnJyw5PmZolS2RI6 # w9rAn1xnF2C/2HVZw37+Ghf+sdR9EgewgPAGoU1bKN4iQVE7FX1B4B6rIuq5Zxje # l2EFyFzkVWFDd+uy62o6WdH8mgwlHySxUkDeUgLLJwjupVKKvm4FCs0r8CE3g5RZ # GkHW6iOVg7QqR4OveGe3BGVK41Gex/iU7WNDWqQ2xqXDywnyFuTQVs/y2b7dPtMd # dbcQ6a/zFQl+WdhhnE5S1Y4Pjfw0TQ/+nKd+jc8lme8eihUbPvETfDLk3j0JI9xd # eXf4plnVMy33qvlLG4GVYzjYU+jNlGK1KCBcBFccFWasLo75Lyk= # =Ocl+ # -----END PGP SIGNATURE----- # gpg: Signature made Mon 04 Nov 2024 10:51:04 GMT # gpg: using RSA key FAABE75E12917221DCFD6BB2E3E32C2CDEADC0DE # gpg: Good signature from "Philippe Mathieu-Daudé (F4BUG) <f4bug@amsat.org>" [full] # Primary key fingerprint: FAAB E75E 1291 7221 DCFD 6BB2 E3E3 2C2C DEAD C0DE * tag 'mips-20241104' of https://github.com/philmd/qemu: target/mips: Remove unused CPUMIPSState::current_fpu field target/mips: Introduce disas_mt_available() target/mips: Introduce ase_3d_available() helper target/mips: Remove unreachable 32-bit code on 64-bit Loongson Ext target/mips: Convert Loongson [D]MULT[U].G opcodes to decodetree target/mips: Convert Loongson [D]MOD[U].G opcodes to decodetree target/mips: Convert Loongson [D]DIVU.G opcodes to decodetree target/mips: Convert Loongson DIV.G opcodes to decodetree target/mips: Convert Loongson DDIV.G opcodes to decodetree target/mips: Re-introduce OPC_ADDUH_QB_DSP and OPC_MUL_PH_DSP target/mips: Simplify Loongson MULTU.G opcode target/mips: Extract decode_64bit_enabled() helper target/mips: Enable MSA ASE for mips32r6-generic target/mips: Migrate TLB MemoryMapID register Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'target')
-rw-r--r--target/mips/cpu-defs.c.inc16
-rw-r--r--target/mips/cpu.h7
-rw-r--r--target/mips/mips-defs.h2
-rw-r--r--target/mips/sysemu/machine.c9
-rw-r--r--target/mips/tcg/godson2.decode27
-rw-r--r--target/mips/tcg/loong-ext.decode28
-rw-r--r--target/mips/tcg/loong_translate.c271
-rw-r--r--target/mips/tcg/meson.build3
-rw-r--r--target/mips/tcg/micromips_translate.c.inc5
-rw-r--r--target/mips/tcg/translate.c415
-rw-r--r--target/mips/tcg/translate.h8
11 files changed, 452 insertions, 339 deletions
diff --git a/target/mips/cpu-defs.c.inc b/target/mips/cpu-defs.c.inc
index fbf787d8ce..922fc39138 100644
--- a/target/mips/cpu-defs.c.inc
+++ b/target/mips/cpu-defs.c.inc
@@ -314,7 +314,7 @@ const mips_def_t mips_defs[] =
(0x3fe << CP0SRSC4_SRS14) | (0x3fe << CP0SRSC4_SRS13),
.SEGBITS = 32,
.PABITS = 32,
- .insn_flags = CPU_MIPS32R2 | ASE_MIPS16 | ASE_DSP | ASE_MT,
+ .insn_flags = CPU_MIPS32R2 | ASE_MIPS16 | ASE_DSP,
.mmu_type = MMU_TYPE_R4000,
},
{
@@ -478,14 +478,15 @@ const mips_def_t mips_defs[] =
(2 << CP0C1_DS) | (4 << CP0C1_DL) | (3 << CP0C1_DA) |
(0 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP),
.CP0_Config2 = MIPS_CONFIG2,
- .CP0_Config3 = MIPS_CONFIG3 | (1 << CP0C3_BP) | (1 << CP0C3_BI) |
+ .CP0_Config3 = MIPS_CONFIG3 | (1 << CP0C3_MSAP) |
+ (1 << CP0C3_BP) | (1 << CP0C3_BI) |
(2 << CP0C3_ISA) | (1 << CP0C3_ULRI) |
(1 << CP0C3_RXI) | (1U << CP0C3_M),
.CP0_Config4 = MIPS_CONFIG4 | (0xfc << CP0C4_KScrExist) |
(3 << CP0C4_IE) | (1U << CP0C4_M),
.CP0_Config5 = MIPS_CONFIG5 | (1 << CP0C5_XNP) | (1 << CP0C5_LLB),
- .CP0_Config5_rw_bitmask = (1 << CP0C5_SBRI) | (1 << CP0C5_FRE) |
- (1 << CP0C5_UFE),
+ .CP0_Config5_rw_bitmask = (1 << CP0C5_MSAEn) | (1 << CP0C5_UFE) |
+ (1 << CP0C5_FRE) | (1 << CP0C5_SBRI),
.CP0_LLAddr_rw_bitmask = 0,
.CP0_LLAddr_shift = 0,
.SYNCI_Step = 32,
@@ -499,6 +500,7 @@ const mips_def_t mips_defs[] =
(1 << FCR0_S) | (0x00 << FCR0_PRID) | (0x0 << FCR0_REV),
.CP1_fcr31 = (1 << FCR31_ABS2008) | (1 << FCR31_NAN2008),
.CP1_fcr31_rw_bitmask = 0x0103FFFF,
+ .MSAIR = 0x03 << MSAIR_ProcID,
.SEGBITS = 32,
.PABITS = 32,
.insn_flags = CPU_MIPS32R6 | ASE_MICROMIPS,
@@ -541,7 +543,7 @@ const mips_def_t mips_defs[] =
.SEGBITS = 32,
.PABITS = 32,
.insn_flags = CPU_MIPS32R6 | ISA_NANOMIPS32 |
- ASE_DSP | ASE_DSP_R2 | ASE_DSP_R3 | ASE_MT,
+ ASE_DSP | ASE_DSP_R2 | ASE_DSP_R3,
.mmu_type = MMU_TYPE_R4000,
},
#if defined(TARGET_MIPS64)
@@ -661,7 +663,7 @@ const mips_def_t mips_defs[] =
.CP1_fcr31_rw_bitmask = 0xFF83FFFF,
.SEGBITS = 40,
.PABITS = 36,
- .insn_flags = CPU_MIPS64R1 | ASE_MIPS3D,
+ .insn_flags = CPU_MIPS64R1,
.mmu_type = MMU_TYPE_R4000,
},
{
@@ -690,7 +692,7 @@ const mips_def_t mips_defs[] =
.CP1_fcr31_rw_bitmask = 0xFF83FFFF,
.SEGBITS = 42,
.PABITS = 36,
- .insn_flags = CPU_MIPS64R2 | ASE_MIPS3D,
+ .insn_flags = CPU_MIPS64R2,
.mmu_type = MMU_TYPE_R4000,
},
{
diff --git a/target/mips/cpu.h b/target/mips/cpu.h
index a4a46ebbe9..f6877ece8b 100644
--- a/target/mips/cpu.h
+++ b/target/mips/cpu.h
@@ -530,7 +530,6 @@ typedef struct CPUArchState {
CPUMIPSFPUContext active_fpu;
uint32_t current_tc;
- uint32_t current_fpu;
uint32_t SEGBITS;
uint32_t PABITS;
@@ -1319,6 +1318,12 @@ bool cpu_type_supports_cps_smp(const char *cpu_type);
bool cpu_supports_isa(const CPUMIPSState *env, uint64_t isa_mask);
bool cpu_type_supports_isa(const char *cpu_type, uint64_t isa);
+/* Check presence of MIPS-3D ASE */
+static inline bool ase_3d_available(const CPUMIPSState *env)
+{
+ return env->active_fpu.fcr0 & (1 << FCR0_3D);
+}
+
/* Check presence of MSA implementation */
static inline bool ase_msa_available(CPUMIPSState *env)
{
diff --git a/target/mips/mips-defs.h b/target/mips/mips-defs.h
index a6cebe0265..9d4d292586 100644
--- a/target/mips/mips-defs.h
+++ b/target/mips/mips-defs.h
@@ -26,12 +26,10 @@
* bits 24-39: MIPS ASEs
*/
#define ASE_MIPS16 0x0000000001000000ULL
-#define ASE_MIPS3D 0x0000000002000000ULL
#define ASE_MDMX 0x0000000004000000ULL
#define ASE_DSP 0x0000000008000000ULL
#define ASE_DSP_R2 0x0000000010000000ULL
#define ASE_DSP_R3 0x0000000020000000ULL
-#define ASE_MT 0x0000000040000000ULL
#define ASE_SMARTMIPS 0x0000000080000000ULL
#define ASE_MICROMIPS 0x0000000100000000ULL
/*
diff --git a/target/mips/sysemu/machine.c b/target/mips/sysemu/machine.c
index 213fd637fc..8af11fd896 100644
--- a/target/mips/sysemu/machine.c
+++ b/target/mips/sysemu/machine.c
@@ -142,6 +142,7 @@ static int get_tlb(QEMUFile *f, void *pv, size_t size,
qemu_get_betls(f, &v->VPN);
qemu_get_be32s(f, &v->PageMask);
qemu_get_be16s(f, &v->ASID);
+ qemu_get_be32s(f, &v->MMID);
qemu_get_be16s(f, &flags);
v->G = (flags >> 10) & 1;
v->C0 = (flags >> 7) & 3;
@@ -167,6 +168,7 @@ static int put_tlb(QEMUFile *f, void *pv, size_t size,
r4k_tlb_t *v = pv;
uint16_t asid = v->ASID;
+ uint32_t mmid = v->MMID;
uint16_t flags = ((v->EHINV << 15) |
(v->RI1 << 14) |
(v->RI0 << 13) |
@@ -183,6 +185,7 @@ static int put_tlb(QEMUFile *f, void *pv, size_t size,
qemu_put_betls(f, &v->VPN);
qemu_put_be32s(f, &v->PageMask);
qemu_put_be16s(f, &asid);
+ qemu_put_be32s(f, &mmid);
qemu_put_be16s(f, &flags);
qemu_put_be64s(f, &v->PFN[0]);
qemu_put_be64s(f, &v->PFN[1]);
@@ -204,8 +207,8 @@ static const VMStateInfo vmstate_info_tlb = {
static const VMStateDescription vmstate_tlb = {
.name = "cpu/tlb",
- .version_id = 2,
- .minimum_version_id = 2,
+ .version_id = 3,
+ .minimum_version_id = 3,
.fields = (const VMStateField[]) {
VMSTATE_UINT32(nb_tlb, CPUMIPSTLBContext),
VMSTATE_UINT32(tlb_in_use, CPUMIPSTLBContext),
@@ -239,7 +242,7 @@ const VMStateDescription vmstate_mips_cpu = {
/* CPU metastate */
VMSTATE_UINT32(env.current_tc, MIPSCPU),
- VMSTATE_UINT32(env.current_fpu, MIPSCPU),
+ VMSTATE_UNUSED(sizeof(uint32_t)), /* was current_fpu */
VMSTATE_INT32(env.error_code, MIPSCPU),
VMSTATE_UINTTL(env.btarget, MIPSCPU),
VMSTATE_UINTTL(env.bcond, MIPSCPU),
diff --git a/target/mips/tcg/godson2.decode b/target/mips/tcg/godson2.decode
new file mode 100644
index 0000000000..25b396b682
--- /dev/null
+++ b/target/mips/tcg/godson2.decode
@@ -0,0 +1,27 @@
+# Godson2 64-bit Integer instructions
+#
+# Copyright (C) 2021 Philippe Mathieu-Daudé
+#
+# SPDX-License-Identifier: LGPL-2.1-or-later
+#
+# Reference:
+# Godson-2E Software Manual
+# (Document Number: godson2e-user-manual-V0.6)
+#
+
+&muldiv rs rt rd
+
+@rs_rt_rd ...... rs:5 rt:5 rd:5 ..... ...... &muldiv
+
+MULTu_G 011111 ..... ..... ..... 00000 01100- @rs_rt_rd
+DMULTu_G 011111 ..... ..... ..... 00000 01110- @rs_rt_rd
+
+DIV_G 011111 ..... ..... ..... 00000 011010 @rs_rt_rd
+DIVU_G 011111 ..... ..... ..... 00000 011011 @rs_rt_rd
+DDIV_G 011111 ..... ..... ..... 00000 011110 @rs_rt_rd
+DDIVU_G 011111 ..... ..... ..... 00000 011111 @rs_rt_rd
+
+MOD_G 011111 ..... ..... ..... 00000 100010 @rs_rt_rd
+MODU_G 011111 ..... ..... ..... 00000 100011 @rs_rt_rd
+DMOD_G 011111 ..... ..... ..... 00000 100110 @rs_rt_rd
+DMODU_G 011111 ..... ..... ..... 00000 100111 @rs_rt_rd
diff --git a/target/mips/tcg/loong-ext.decode b/target/mips/tcg/loong-ext.decode
new file mode 100644
index 0000000000..b43979d0ef
--- /dev/null
+++ b/target/mips/tcg/loong-ext.decode
@@ -0,0 +1,28 @@
+# Loongson 64-bit Extension instructions
+#
+# Copyright (C) 2021 Philippe Mathieu-Daudé
+#
+# SPDX-License-Identifier: LGPL-2.1-or-later
+#
+# Reference:
+# STLS2F01 User Manual
+# Appendix A: new integer instructions
+# (Document Number: UM0447)
+#
+
+&muldiv rs rt rd !extern
+
+@rs_rt_rd ...... rs:5 rt:5 rd:5 ..... ...... &muldiv
+
+MULTu_G 011100 ..... ..... ..... 00000 0100-0 @rs_rt_rd
+DMULTu_G 011100 ..... ..... ..... 00000 0100-1 @rs_rt_rd
+
+DIV_G 011100 ..... ..... ..... 00000 010100 @rs_rt_rd
+DDIV_G 011100 ..... ..... ..... 00000 010101 @rs_rt_rd
+DIVU_G 011100 ..... ..... ..... 00000 010110 @rs_rt_rd
+DDIVU_G 011100 ..... ..... ..... 00000 010111 @rs_rt_rd
+
+MOD_G 011100 ..... ..... ..... 00000 011100 @rs_rt_rd
+DMOD_G 011100 ..... ..... ..... 00000 011101 @rs_rt_rd
+MODU_G 011100 ..... ..... ..... 00000 011110 @rs_rt_rd
+DMODU_G 011100 ..... ..... ..... 00000 011111 @rs_rt_rd
diff --git a/target/mips/tcg/loong_translate.c b/target/mips/tcg/loong_translate.c
new file mode 100644
index 0000000000..7d74cc34f8
--- /dev/null
+++ b/target/mips/tcg/loong_translate.c
@@ -0,0 +1,271 @@
+/*
+ * MIPS Loongson 64-bit translation routines
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ * Copyright (c) 2006 Marius Groeger (FPU operations)
+ * Copyright (c) 2006 Thiemo Seufer (MIPS32R2 support)
+ * Copyright (c) 2011 Richard Henderson <rth@twiddle.net>
+ * Copyright (c) 2021 Philippe Mathieu-Daudé
+ *
+ * This code is licensed under the GNU GPLv2 and later.
+ */
+
+#include "qemu/osdep.h"
+#include "translate.h"
+
+/* Include the auto-generated decoder. */
+#include "decode-godson2.c.inc"
+#include "decode-loong-ext.c.inc"
+
+/*
+ * Word or double-word Fixed-point instructions.
+ * ---------------------------------------------
+ *
+ * Fixed-point multiplies and divisions write only
+ * one result into general-purpose registers.
+ */
+
+static bool gen_lext_DIV_G(DisasContext *s, int rd, int rs, int rt,
+ bool is_double)
+{
+ TCGv t0, t1;
+ TCGLabel *l1, *l2, *l3;
+
+ if (rd == 0) {
+ /* Treat as NOP. */
+ return true;
+ }
+
+ t0 = tcg_temp_new();
+ t1 = tcg_temp_new();
+ l1 = gen_new_label();
+ l2 = gen_new_label();
+ l3 = gen_new_label();
+
+ gen_load_gpr(t0, rs);
+ gen_load_gpr(t1, rt);
+
+ if (!is_double) {
+ tcg_gen_ext32s_tl(t0, t0);
+ tcg_gen_ext32s_tl(t1, t1);
+ }
+ tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1);
+ tcg_gen_movi_tl(cpu_gpr[rd], 0);
+ tcg_gen_br(l3);
+ gen_set_label(l1);
+
+ tcg_gen_brcondi_tl(TCG_COND_NE, t0, is_double ? LLONG_MIN : INT_MIN, l2);
+ tcg_gen_brcondi_tl(TCG_COND_NE, t1, -1LL, l2);
+ tcg_gen_mov_tl(cpu_gpr[rd], t0);
+
+ tcg_gen_br(l3);
+ gen_set_label(l2);
+ tcg_gen_div_tl(cpu_gpr[rd], t0, t1);
+ if (!is_double) {
+ tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
+ }
+ gen_set_label(l3);
+
+ return true;
+}
+
+static bool trans_DIV_G(DisasContext *s, arg_muldiv *a)
+{
+ return gen_lext_DIV_G(s, a->rd, a->rs, a->rt, false);
+}
+
+static bool trans_DDIV_G(DisasContext *s, arg_muldiv *a)
+{
+ return gen_lext_DIV_G(s, a->rd, a->rs, a->rt, true);
+}
+
+static bool gen_lext_DIVU_G(DisasContext *s, int rd, int rs, int rt,
+ bool is_double)
+{
+ TCGv t0, t1;
+ TCGLabel *l1, *l2;
+
+ if (rd == 0) {
+ /* Treat as NOP. */
+ return true;
+ }
+
+ t0 = tcg_temp_new();
+ t1 = tcg_temp_new();
+ l1 = gen_new_label();
+ l2 = gen_new_label();
+
+ gen_load_gpr(t0, rs);
+ gen_load_gpr(t1, rt);
+
+ if (!is_double) {
+ tcg_gen_ext32u_tl(t0, t0);
+ tcg_gen_ext32u_tl(t1, t1);
+ }
+ tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1);
+ tcg_gen_movi_tl(cpu_gpr[rd], 0);
+
+ tcg_gen_br(l2);
+ gen_set_label(l1);
+ tcg_gen_divu_tl(cpu_gpr[rd], t0, t1);
+ if (!is_double) {
+ tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
+ }
+ gen_set_label(l2);
+
+ return true;
+}
+
+static bool trans_DIVU_G(DisasContext *s, arg_muldiv *a)
+{
+ return gen_lext_DIVU_G(s, a->rd, a->rs, a->rt, false);
+}
+
+static bool trans_DDIVU_G(DisasContext *s, arg_muldiv *a)
+{
+ return gen_lext_DIVU_G(s, a->rd, a->rs, a->rt, true);
+}
+
+static bool gen_lext_MOD_G(DisasContext *s, int rd, int rs, int rt,
+ bool is_double)
+{
+ TCGv t0, t1;
+ TCGLabel *l1, *l2, *l3;
+
+ if (rd == 0) {
+ /* Treat as NOP. */
+ return true;
+ }
+
+ t0 = tcg_temp_new();
+ t1 = tcg_temp_new();
+ l1 = gen_new_label();
+ l2 = gen_new_label();
+ l3 = gen_new_label();
+
+ gen_load_gpr(t0, rs);
+ gen_load_gpr(t1, rt);
+
+ if (!is_double) {
+ tcg_gen_ext32u_tl(t0, t0);
+ tcg_gen_ext32u_tl(t1, t1);
+ }
+ tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1);
+ tcg_gen_brcondi_tl(TCG_COND_NE, t0, is_double ? LLONG_MIN : INT_MIN, l2);
+ tcg_gen_brcondi_tl(TCG_COND_NE, t1, -1LL, l2);
+ gen_set_label(l1);
+ tcg_gen_movi_tl(cpu_gpr[rd], 0);
+ tcg_gen_br(l3);
+ gen_set_label(l2);
+ tcg_gen_rem_tl(cpu_gpr[rd], t0, t1);
+ if (!is_double) {
+ tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
+ }
+ gen_set_label(l3);
+
+ return true;
+}
+
+static bool trans_MOD_G(DisasContext *s, arg_muldiv *a)
+{
+ return gen_lext_MOD_G(s, a->rd, a->rs, a->rt, false);
+}
+
+static bool trans_DMOD_G(DisasContext *s, arg_muldiv *a)
+{
+ return gen_lext_MOD_G(s, a->rd, a->rs, a->rt, true);
+}
+
+static bool gen_lext_MODU_G(DisasContext *s, int rd, int rs, int rt,
+ bool is_double)
+{
+ TCGv t0, t1;
+ TCGLabel *l1, *l2;
+
+ if (rd == 0) {
+ /* Treat as NOP. */
+ return true;
+ }
+
+ t0 = tcg_temp_new();
+ t1 = tcg_temp_new();
+ l1 = gen_new_label();
+ l2 = gen_new_label();
+
+ gen_load_gpr(t0, rs);
+ gen_load_gpr(t1, rt);
+
+ if (!is_double) {
+ tcg_gen_ext32u_tl(t0, t0);
+ tcg_gen_ext32u_tl(t1, t1);
+ }
+ tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1);
+ tcg_gen_movi_tl(cpu_gpr[rd], 0);
+ tcg_gen_br(l2);
+ gen_set_label(l1);
+ tcg_gen_remu_tl(cpu_gpr[rd], t0, t1);
+ if (!is_double) {
+ tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
+ }
+ gen_set_label(l2);
+
+ return true;
+}
+
+static bool trans_MODU_G(DisasContext *s, arg_muldiv *a)
+{
+ return gen_lext_MODU_G(s, a->rd, a->rs, a->rt, false);
+}
+
+static bool trans_DMODU_G(DisasContext *s, arg_muldiv *a)
+{
+ return gen_lext_MODU_G(s, a->rd, a->rs, a->rt, true);
+}
+
+static bool gen_lext_MULT_G(DisasContext *s, int rd, int rs, int rt,
+ bool is_double)
+{
+ TCGv t0, t1;
+
+ if (rd == 0) {
+ /* Treat as NOP. */
+ return true;
+ }
+
+ t0 = tcg_temp_new();
+ t1 = tcg_temp_new();
+
+ gen_load_gpr(t0, rs);
+ gen_load_gpr(t1, rt);
+
+ tcg_gen_mul_tl(cpu_gpr[rd], t0, t1);
+ if (!is_double) {
+ tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
+ }
+
+ return true;
+}
+
+static bool trans_MULTu_G(DisasContext *s, arg_muldiv *a)
+{
+ return gen_lext_MULT_G(s, a->rd, a->rs, a->rt, false);
+}
+
+static bool trans_DMULTu_G(DisasContext *s, arg_muldiv *a)
+{
+ return gen_lext_MULT_G(s, a->rd, a->rs, a->rt, true);
+}
+
+bool decode_ext_loongson(DisasContext *ctx, uint32_t insn)
+{
+ if (!decode_64bit_enabled(ctx)) {
+ return false;
+ }
+ if ((ctx->insn_flags & INSN_LOONGSON2E) && decode_godson2(ctx, ctx->opcode)) {
+ return true;
+ }
+ if ((ctx->insn_flags & ASE_LEXT) && decode_loong_ext(ctx, ctx->opcode)) {
+ return true;
+ }
+ return false;
+}
diff --git a/target/mips/tcg/meson.build b/target/mips/tcg/meson.build
index ea7fb582f2..7b18e6c4c8 100644
--- a/target/mips/tcg/meson.build
+++ b/target/mips/tcg/meson.build
@@ -5,6 +5,8 @@ gen = [
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'),
+ decodetree.process('godson2.decode', extra_args: ['--static-decode=decode_godson2']),
+ decodetree.process('loong-ext.decode', extra_args: ['--static-decode=decode_loong_ext']),
]
mips_ss.add(gen)
@@ -28,6 +30,7 @@ mips_ss.add(when: 'TARGET_MIPS64', if_true: files(
'tx79_translate.c',
'octeon_translate.c',
'lcsr_translate.c',
+ 'loong_translate.c',
), if_false: files(
'mxu_translate.c',
))
diff --git a/target/mips/tcg/micromips_translate.c.inc b/target/mips/tcg/micromips_translate.c.inc
index 3cbf53bf2b..c479bec108 100644
--- a/target/mips/tcg/micromips_translate.c.inc
+++ b/target/mips/tcg/micromips_translate.c.inc
@@ -2484,7 +2484,10 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx)
mips32_op = OPC_BC1TANY4;
do_cp1mips3d:
check_cop1x(ctx);
- check_insn(ctx, ASE_MIPS3D);
+ if (!ase_3d_available(env)) {
+ gen_reserved_instruction(ctx);
+ break;
+ }
/* Fall through */
do_cp1branch:
if (env->CP0_Config1 & (1 << CP0C1_FP)) {
diff --git a/target/mips/tcg/translate.c b/target/mips/tcg/translate.c
index d92fc418ed..de7045874d 100644
--- a/target/mips/tcg/translate.c
+++ b/target/mips/tcg/translate.c
@@ -327,19 +327,6 @@ enum {
OPC_MUL = 0x02 | OPC_SPECIAL2,
OPC_MSUB = 0x04 | OPC_SPECIAL2,
OPC_MSUBU = 0x05 | OPC_SPECIAL2,
- /* Loongson 2F */
- OPC_MULT_G_2F = 0x10 | OPC_SPECIAL2,
- OPC_DMULT_G_2F = 0x11 | OPC_SPECIAL2,
- OPC_MULTU_G_2F = 0x12 | OPC_SPECIAL2,
- OPC_DMULTU_G_2F = 0x13 | OPC_SPECIAL2,
- OPC_DIV_G_2F = 0x14 | OPC_SPECIAL2,
- OPC_DDIV_G_2F = 0x15 | OPC_SPECIAL2,
- OPC_DIVU_G_2F = 0x16 | OPC_SPECIAL2,
- OPC_DDIVU_G_2F = 0x17 | OPC_SPECIAL2,
- OPC_MOD_G_2F = 0x1c | OPC_SPECIAL2,
- OPC_DMOD_G_2F = 0x1d | OPC_SPECIAL2,
- OPC_MODU_G_2F = 0x1e | OPC_SPECIAL2,
- OPC_DMODU_G_2F = 0x1f | OPC_SPECIAL2,
/* Misc */
OPC_CLZ = 0x20 | OPC_SPECIAL2,
OPC_CLO = 0x21 | OPC_SPECIAL2,
@@ -368,20 +355,6 @@ enum {
OPC_RDHWR = 0x3B | OPC_SPECIAL3,
OPC_GINV = 0x3D | OPC_SPECIAL3,
- /* Loongson 2E */
- OPC_MULT_G_2E = 0x18 | OPC_SPECIAL3,
- OPC_MULTU_G_2E = 0x19 | OPC_SPECIAL3,
- OPC_DIV_G_2E = 0x1A | OPC_SPECIAL3,
- OPC_DIVU_G_2E = 0x1B | OPC_SPECIAL3,
- OPC_DMULT_G_2E = 0x1C | OPC_SPECIAL3,
- OPC_DMULTU_G_2E = 0x1D | OPC_SPECIAL3,
- OPC_DDIV_G_2E = 0x1E | OPC_SPECIAL3,
- OPC_DDIVU_G_2E = 0x1F | OPC_SPECIAL3,
- OPC_MOD_G_2E = 0x22 | OPC_SPECIAL3,
- OPC_MODU_G_2E = 0x23 | OPC_SPECIAL3,
- OPC_DMOD_G_2E = 0x26 | OPC_SPECIAL3,
- OPC_DMODU_G_2E = 0x27 | OPC_SPECIAL3,
-
/* MIPS DSP Load */
OPC_LX_DSP = 0x0A | OPC_SPECIAL3,
/* MIPS DSP Arithmetic */
@@ -389,16 +362,14 @@ enum {
OPC_ADDU_OB_DSP = 0x14 | OPC_SPECIAL3,
OPC_ABSQ_S_PH_DSP = 0x12 | OPC_SPECIAL3,
OPC_ABSQ_S_QH_DSP = 0x16 | OPC_SPECIAL3,
- /* OPC_ADDUH_QB_DSP is same as OPC_MULT_G_2E. */
- /* OPC_ADDUH_QB_DSP = 0x18 | OPC_SPECIAL3, */
+ OPC_ADDUH_QB_DSP = 0x18 | OPC_SPECIAL3,
OPC_CMPU_EQ_QB_DSP = 0x11 | OPC_SPECIAL3,
OPC_CMPU_EQ_OB_DSP = 0x15 | OPC_SPECIAL3,
/* MIPS DSP GPR-Based Shift Sub-class */
OPC_SHLL_QB_DSP = 0x13 | OPC_SPECIAL3,
OPC_SHLL_OB_DSP = 0x17 | OPC_SPECIAL3,
/* MIPS DSP Multiply Sub-class insns */
- /* OPC_MUL_PH_DSP is same as OPC_ADDUH_QB_DSP. */
- /* OPC_MUL_PH_DSP = 0x18 | OPC_SPECIAL3, */
+ OPC_MUL_PH_DSP = 0x18 | OPC_SPECIAL3,
OPC_DPA_W_PH_DSP = 0x30 | OPC_SPECIAL3,
OPC_DPAQ_W_QH_DSP = 0x34 | OPC_SPECIAL3,
/* DSP Bit/Manipulation Sub-class */
@@ -556,7 +527,6 @@ enum {
OPC_MULQ_S_PH = (0x1E << 6) | OPC_ADDU_QB_DSP,
};
-#define OPC_ADDUH_QB_DSP OPC_MULT_G_2E
#define MASK_ADDUH_QB(op) (MASK_SPECIAL3(op) | (op & (0x1F << 6)))
enum {
/* MIPS DSP Arithmetic Sub-class */
@@ -1645,13 +1615,18 @@ static inline void check_ps(DisasContext *ctx)
check_cp1_64bitmode(ctx);
}
+bool decode_64bit_enabled(DisasContext *ctx)
+{
+ return ctx->hflags & MIPS_HFLAG_64;
+}
+
/*
* This code generates a "reserved instruction" exception if cpu is not
* 64-bit or 64-bit instructions are not enabled.
*/
void check_mips_64(DisasContext *ctx)
{
- if (unlikely((TARGET_LONG_BITS != 64) || !(ctx->hflags & MIPS_HFLAG_64))) {
+ if (unlikely((TARGET_LONG_BITS != 64) || !decode_64bit_enabled(ctx))) {
gen_reserved_instruction(ctx);
}
}
@@ -3586,184 +3561,6 @@ static void gen_cl(DisasContext *ctx, uint32_t opc,
}
}
-/* Godson integer instructions */
-static void gen_loongson_integer(DisasContext *ctx, uint32_t opc,
- int rd, int rs, int rt)
-{
- TCGv t0, t1;
-
- if (rd == 0) {
- /* Treat as NOP. */
- return;
- }
-
- t0 = tcg_temp_new();
- t1 = tcg_temp_new();
- gen_load_gpr(t0, rs);
- gen_load_gpr(t1, rt);
-
- switch (opc) {
- case OPC_MULT_G_2E:
- case OPC_MULT_G_2F:
- tcg_gen_mul_tl(cpu_gpr[rd], t0, t1);
- tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
- break;
- case OPC_MULTU_G_2E:
- case OPC_MULTU_G_2F:
- tcg_gen_ext32u_tl(t0, t0);
- tcg_gen_ext32u_tl(t1, t1);
- tcg_gen_mul_tl(cpu_gpr[rd], t0, t1);
- tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
- break;
- case OPC_DIV_G_2E:
- case OPC_DIV_G_2F:
- {
- TCGLabel *l1 = gen_new_label();
- TCGLabel *l2 = gen_new_label();
- TCGLabel *l3 = gen_new_label();
- tcg_gen_ext32s_tl(t0, t0);
- tcg_gen_ext32s_tl(t1, t1);
- tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1);
- tcg_gen_movi_tl(cpu_gpr[rd], 0);
- tcg_gen_br(l3);
- gen_set_label(l1);
- tcg_gen_brcondi_tl(TCG_COND_NE, t0, INT_MIN, l2);
- tcg_gen_brcondi_tl(TCG_COND_NE, t1, -1, l2);
- tcg_gen_mov_tl(cpu_gpr[rd], t0);
- tcg_gen_br(l3);
- gen_set_label(l2);
- tcg_gen_div_tl(cpu_gpr[rd], t0, t1);
- tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
- gen_set_label(l3);
- }
- break;
- case OPC_DIVU_G_2E:
- case OPC_DIVU_G_2F:
- {
- TCGLabel *l1 = gen_new_label();
- TCGLabel *l2 = gen_new_label();
- tcg_gen_ext32u_tl(t0, t0);
- tcg_gen_ext32u_tl(t1, t1);
- tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1);
- tcg_gen_movi_tl(cpu_gpr[rd], 0);
- tcg_gen_br(l2);
- gen_set_label(l1);
- tcg_gen_divu_tl(cpu_gpr[rd], t0, t1);
- tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
- gen_set_label(l2);
- }
- break;
- case OPC_MOD_G_2E:
- case OPC_MOD_G_2F:
- {
- TCGLabel *l1 = gen_new_label();
- TCGLabel *l2 = gen_new_label();
- TCGLabel *l3 = gen_new_label();
- tcg_gen_ext32u_tl(t0, t0);
- tcg_gen_ext32u_tl(t1, t1);
- tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1);
- tcg_gen_brcondi_tl(TCG_COND_NE, t0, INT_MIN, l2);
- tcg_gen_brcondi_tl(TCG_COND_NE, t1, -1, l2);
- gen_set_label(l1);
- tcg_gen_movi_tl(cpu_gpr[rd], 0);
- tcg_gen_br(l3);
- gen_set_label(l2);
- tcg_gen_rem_tl(cpu_gpr[rd], t0, t1);
- tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
- gen_set_label(l3);
- }
- break;
- case OPC_MODU_G_2E:
- case OPC_MODU_G_2F:
- {
- TCGLabel *l1 = gen_new_label();
- TCGLabel *l2 = gen_new_label();
- tcg_gen_ext32u_tl(t0, t0);
- tcg_gen_ext32u_tl(t1, t1);
- tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1);
- tcg_gen_movi_tl(cpu_gpr[rd], 0);
- tcg_gen_br(l2);
- gen_set_label(l1);
- tcg_gen_remu_tl(cpu_gpr[rd], t0, t1);
- tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
- gen_set_label(l2);
- }
- break;
-#if defined(TARGET_MIPS64)
- case OPC_DMULT_G_2E:
- case OPC_DMULT_G_2F:
- tcg_gen_mul_tl(cpu_gpr[rd], t0, t1);
- break;
- case OPC_DMULTU_G_2E:
- case OPC_DMULTU_G_2F:
- tcg_gen_mul_tl(cpu_gpr[rd], t0, t1);
- break;
- case OPC_DDIV_G_2E:
- case OPC_DDIV_G_2F:
- {
- TCGLabel *l1 = gen_new_label();
- TCGLabel *l2 = gen_new_label();
- TCGLabel *l3 = gen_new_label();
- tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1);
- tcg_gen_movi_tl(cpu_gpr[rd], 0);
- tcg_gen_br(l3);
- gen_set_label(l1);
- tcg_gen_brcondi_tl(TCG_COND_NE, t0, -1LL << 63, l2);
- tcg_gen_brcondi_tl(TCG_COND_NE, t1, -1LL, l2);
- tcg_gen_mov_tl(cpu_gpr[rd], t0);
- tcg_gen_br(l3);
- gen_set_label(l2);
- tcg_gen_div_tl(cpu_gpr[rd], t0, t1);
- gen_set_label(l3);
- }
- break;
- case OPC_DDIVU_G_2E:
- case OPC_DDIVU_G_2F:
- {
- TCGLabel *l1 = gen_new_label();
- TCGLabel *l2 = gen_new_label();
- tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1);
- tcg_gen_movi_tl(cpu_gpr[rd], 0);
- tcg_gen_br(l2);
- gen_set_label(l1);
- tcg_gen_divu_tl(cpu_gpr[rd], t0, t1);
- gen_set_label(l2);
- }
- break;
- case OPC_DMOD_G_2E:
- case OPC_DMOD_G_2F:
- {
- TCGLabel *l1 = gen_new_label();
- TCGLabel *l2 = gen_new_label();
- TCGLabel *l3 = gen_new_label();
- tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1);
- tcg_gen_brcondi_tl(TCG_COND_NE, t0, -1LL << 63, l2);
- tcg_gen_brcondi_tl(TCG_COND_NE, t1, -1LL, l2);
- gen_set_label(l1);
- tcg_gen_movi_tl(cpu_gpr[rd], 0);
- tcg_gen_br(l3);
- gen_set_label(l2);
- tcg_gen_rem_tl(cpu_gpr[rd], t0, t1);
- gen_set_label(l3);
- }
- break;
- case OPC_DMODU_G_2E:
- case OPC_DMODU_G_2F:
- {
- TCGLabel *l1 = gen_new_label();
- TCGLabel *l2 = gen_new_label();
- tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1);
- tcg_gen_movi_tl(cpu_gpr[rd], 0);
- tcg_gen_br(l2);
- gen_set_label(l1);
- tcg_gen_remu_tl(cpu_gpr[rd], t0, t1);
- gen_set_label(l2);
- }
- break;
-#endif
- }
-}
-
/* Loongson multimedia instructions */
static void gen_loongson_multimedia(DisasContext *ctx, int rd, int rs, int rt)
{
@@ -5315,17 +5112,17 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
register_name = "Index";
break;
case CP0_REG00__MVPCONTROL:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_helper_mfc0_mvpcontrol(arg, tcg_env);
register_name = "MVPControl";
break;
case CP0_REG00__MVPCONF0:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_helper_mfc0_mvpconf0(arg, tcg_env);
register_name = "MVPConf0";
break;
case CP0_REG00__MVPCONF1:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_helper_mfc0_mvpconf1(arg, tcg_env);
register_name = "MVPConf1";
break;
@@ -5346,37 +5143,37 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
register_name = "Random";
break;
case CP0_REG01__VPECONTROL:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEControl));
register_name = "VPEControl";
break;
case CP0_REG01__VPECONF0:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEConf0));
register_name = "VPEConf0";
break;
case CP0_REG01__VPECONF1:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEConf1));
register_name = "VPEConf1";
break;
case CP0_REG01__YQMASK:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_mfc0_load64(arg, offsetof(CPUMIPSState, CP0_YQMask));
register_name = "YQMask";
break;
case CP0_REG01__VPESCHEDULE:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_mfc0_load64(arg, offsetof(CPUMIPSState, CP0_VPESchedule));
register_name = "VPESchedule";
break;
case CP0_REG01__VPESCHEFBACK:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_mfc0_load64(arg, offsetof(CPUMIPSState, CP0_VPEScheFBack));
register_name = "VPEScheFBack";
break;
case CP0_REG01__VPEOPT:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEOpt));
register_name = "VPEOpt";
break;
@@ -5403,37 +5200,37 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
register_name = "EntryLo0";
break;
case CP0_REG02__TCSTATUS:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_helper_mfc0_tcstatus(arg, tcg_env);
register_name = "TCStatus";
break;
case CP0_REG02__TCBIND:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_helper_mfc0_tcbind(arg, tcg_env);
register_name = "TCBind";
break;
case CP0_REG02__TCRESTART:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_helper_mfc0_tcrestart(arg, tcg_env);
register_name = "TCRestart";
break;
case CP0_REG02__TCHALT:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_helper_mfc0_tchalt(arg, tcg_env);
register_name = "TCHalt";
break;
case CP0_REG02__TCCONTEXT:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_helper_mfc0_tccontext(arg, tcg_env);
register_name = "TCContext";
break;
case CP0_REG02__TCSCHEDULE:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_helper_mfc0_tcschedule(arg, tcg_env);
register_name = "TCSchedule";
break;
case CP0_REG02__TCSCHEFBACK:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_helper_mfc0_tcschefback(arg, tcg_env);
register_name = "TCScheFBack";
break;
@@ -6072,17 +5869,17 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
register_name = "Index";
break;
case CP0_REG00__MVPCONTROL:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_helper_mtc0_mvpcontrol(tcg_env, arg);
register_name = "MVPControl";
break;
case CP0_REG00__MVPCONF0:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
/* ignored */
register_name = "MVPConf0";
break;
case CP0_REG00__MVPCONF1:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
/* ignored */
register_name = "MVPConf1";
break;
@@ -6102,39 +5899,39 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
register_name = "Random";
break;
case CP0_REG01__VPECONTROL:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_helper_mtc0_vpecontrol(tcg_env, arg);
register_name = "VPEControl";
break;
case CP0_REG01__VPECONF0:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_helper_mtc0_vpeconf0(tcg_env, arg);
register_name = "VPEConf0";
break;
case CP0_REG01__VPECONF1:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_helper_mtc0_vpeconf1(tcg_env, arg);
register_name = "VPEConf1";
break;
case CP0_REG01__YQMASK:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_helper_mtc0_yqmask(tcg_env, arg);
register_name = "YQMask";
break;
case CP0_REG01__VPESCHEDULE:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
tcg_gen_st_tl(arg, tcg_env,
offsetof(CPUMIPSState, CP0_VPESchedule));
register_name = "VPESchedule";
break;
case CP0_REG01__VPESCHEFBACK:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
tcg_gen_st_tl(arg, tcg_env,
offsetof(CPUMIPSState, CP0_VPEScheFBack));
register_name = "VPEScheFBack";
break;
case CP0_REG01__VPEOPT:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_helper_mtc0_vpeopt(tcg_env, arg);
register_name = "VPEOpt";
break;
@@ -6149,37 +5946,37 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
register_name = "EntryLo0";
break;
case CP0_REG02__TCSTATUS:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_helper_mtc0_tcstatus(tcg_env, arg);
register_name = "TCStatus";
break;
case CP0_REG02__TCBIND:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_helper_mtc0_tcbind(tcg_env, arg);
register_name = "TCBind";
break;
case CP0_REG02__TCRESTART:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_helper_mtc0_tcrestart(tcg_env, arg);
register_name = "TCRestart";
break;
case CP0_REG02__TCHALT:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_helper_mtc0_tchalt(tcg_env, arg);
register_name = "TCHalt";
break;
case CP0_REG02__TCCONTEXT:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_helper_mtc0_tccontext(tcg_env, arg);
register_name = "TCContext";
break;
case CP0_REG02__TCSCHEDULE:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_helper_mtc0_tcschedule(tcg_env, arg);
register_name = "TCSchedule";
break;
case CP0_REG02__TCSCHEFBACK:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_helper_mtc0_tcschefback(tcg_env, arg);
register_name = "TCScheFBack";
break;
@@ -6822,17 +6619,17 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
register_name = "Index";
break;
case CP0_REG00__MVPCONTROL:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_helper_mfc0_mvpcontrol(arg, tcg_env);
register_name = "MVPControl";
break;
case CP0_REG00__MVPCONF0:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_helper_mfc0_mvpconf0(arg, tcg_env);
register_name = "MVPConf0";
break;
case CP0_REG00__MVPCONF1:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_helper_mfc0_mvpconf1(arg, tcg_env);
register_name = "MVPConf1";
break;
@@ -6853,40 +6650,40 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
register_name = "Random";
break;
case CP0_REG01__VPECONTROL:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEControl));
register_name = "VPEControl";
break;
case CP0_REG01__VPECONF0:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEConf0));
register_name = "VPEConf0";
break;
case CP0_REG01__VPECONF1:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEConf1));
register_name = "VPEConf1";
break;
case CP0_REG01__YQMASK:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
tcg_gen_ld_tl(arg, tcg_env,
offsetof(CPUMIPSState, CP0_YQMask));
register_name = "YQMask";
break;
case CP0_REG01__VPESCHEDULE:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
tcg_gen_ld_tl(arg, tcg_env,
offsetof(CPUMIPSState, CP0_VPESchedule));
register_name = "VPESchedule";
break;
case CP0_REG01__VPESCHEFBACK:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
tcg_gen_ld_tl(arg, tcg_env,
offsetof(CPUMIPSState, CP0_VPEScheFBack));
register_name = "VPEScheFBack";
break;
case CP0_REG01__VPEOPT:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEOpt));
register_name = "VPEOpt";
break;
@@ -6902,37 +6699,37 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
register_name = "EntryLo0";
break;
case CP0_REG02__TCSTATUS:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_helper_mfc0_tcstatus(arg, tcg_env);
register_name = "TCStatus";
break;
case CP0_REG02__TCBIND:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_helper_mfc0_tcbind(arg, tcg_env);
register_name = "TCBind";
break;
case CP0_REG02__TCRESTART:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_helper_dmfc0_tcrestart(arg, tcg_env);
register_name = "TCRestart";
break;
case CP0_REG02__TCHALT:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_helper_dmfc0_tchalt(arg, tcg_env);
register_name = "TCHalt";
break;
case CP0_REG02__TCCONTEXT:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_helper_dmfc0_tccontext(arg, tcg_env);
register_name = "TCContext";
break;
case CP0_REG02__TCSCHEDULE:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_helper_dmfc0_tcschedule(arg, tcg_env);
register_name = "TCSchedule";
break;
case CP0_REG02__TCSCHEFBACK:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_helper_dmfc0_tcschefback(arg, tcg_env);
register_name = "TCScheFBack";
break;
@@ -7539,17 +7336,17 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
register_name = "Index";
break;
case CP0_REG00__MVPCONTROL:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_helper_mtc0_mvpcontrol(tcg_env, arg);
register_name = "MVPControl";
break;
case CP0_REG00__MVPCONF0:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
/* ignored */
register_name = "MVPConf0";
break;
case CP0_REG00__MVPCONF1:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
/* ignored */
register_name = "MVPConf1";
break;
@@ -7569,39 +7366,39 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
register_name = "Random";
break;
case CP0_REG01__VPECONTROL:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_helper_mtc0_vpecontrol(tcg_env, arg);
register_name = "VPEControl";
break;
case CP0_REG01__VPECONF0:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_helper_mtc0_vpeconf0(tcg_env, arg);
register_name = "VPEConf0";
break;
case CP0_REG01__VPECONF1:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_helper_mtc0_vpeconf1(tcg_env, arg);
register_name = "VPEConf1";
break;
case CP0_REG01__YQMASK:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_helper_mtc0_yqmask(tcg_env, arg);
register_name = "YQMask";
break;
case CP0_REG01__VPESCHEDULE:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
tcg_gen_st_tl(arg, tcg_env,
offsetof(CPUMIPSState, CP0_VPESchedule));
register_name = "VPESchedule";
break;
case CP0_REG01__VPESCHEFBACK:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
tcg_gen_st_tl(arg, tcg_env,
offsetof(CPUMIPSState, CP0_VPEScheFBack));
register_name = "VPEScheFBack";
break;
case CP0_REG01__VPEOPT:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_helper_mtc0_vpeopt(tcg_env, arg);
register_name = "VPEOpt";
break;
@@ -7616,37 +7413,37 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
register_name = "EntryLo0";
break;
case CP0_REG02__TCSTATUS:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_helper_mtc0_tcstatus(tcg_env, arg);
register_name = "TCStatus";
break;
case CP0_REG02__TCBIND:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_helper_mtc0_tcbind(tcg_env, arg);
register_name = "TCBind";
break;
case CP0_REG02__TCRESTART:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_helper_mtc0_tcrestart(tcg_env, arg);
register_name = "TCRestart";
break;
case CP0_REG02__TCHALT:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_helper_mtc0_tchalt(tcg_env, arg);
register_name = "TCHalt";
break;
case CP0_REG02__TCCONTEXT:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_helper_mtc0_tccontext(tcg_env, arg);
register_name = "TCContext";
break;
case CP0_REG02__TCSCHEDULE:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_helper_mtc0_tcschedule(tcg_env, arg);
register_name = "TCSchedule";
break;
case CP0_REG02__TCSCHEFBACK:
- CP0_CHECK(ctx->insn_flags & ASE_MT);
+ CP0_CHECK(disas_mt_available(ctx));
gen_helper_mtc0_tcschefback(tcg_env, arg);
register_name = "TCScheFBack";
break;
@@ -11584,8 +11381,7 @@ static void gen_mipsdsp_arith(DisasContext *ctx, uint32_t op1, uint32_t op2,
gen_load_gpr(v2_t, v2);
switch (op1) {
- /* OPC_MULT_G_2E is equal OPC_ADDUH_QB_DSP */
- case OPC_MULT_G_2E:
+ case OPC_ADDUH_QB_DSP:
check_dsp_r2(ctx);
switch (op2) {
case OPC_ADDUH_QB:
@@ -12268,11 +12064,7 @@ static void gen_mipsdsp_multiply(DisasContext *ctx, uint32_t op1, uint32_t op2,
gen_load_gpr(v2_t, v2);
switch (op1) {
- /*
- * OPC_MULT_G_2E, OPC_ADDUH_QB_DSP, OPC_MUL_PH_DSP have
- * the same mask and op1.
- */
- case OPC_MULT_G_2E:
+ case OPC_MUL_PH_DSP:
check_dsp_r2(ctx);
switch (op2) {
case OPC_MUL_PH:
@@ -13624,15 +13416,6 @@ static void decode_opc_special2_legacy(CPUMIPSState *env, DisasContext *ctx)
case OPC_MUL:
gen_arith(ctx, op1, rd, rs, rt);
break;
- case OPC_DIV_G_2F:
- case OPC_DIVU_G_2F:
- case OPC_MULT_G_2F:
- case OPC_MULTU_G_2F:
- case OPC_MOD_G_2F:
- case OPC_MODU_G_2F:
- check_insn(ctx, INSN_LOONGSON2F | ASE_LEXT);
- gen_loongson_integer(ctx, op1, rd, rs, rt);
- break;
case OPC_CLO:
case OPC_CLZ:
check_insn(ctx, ISA_MIPS_R1);
@@ -13657,15 +13440,6 @@ static void decode_opc_special2_legacy(CPUMIPSState *env, DisasContext *ctx)
check_mips_64(ctx);
gen_cl(ctx, op1, rd, rs);
break;
- case OPC_DMULT_G_2F:
- case OPC_DMULTU_G_2F:
- case OPC_DDIV_G_2F:
- case OPC_DDIVU_G_2F:
- case OPC_DMOD_G_2F:
- case OPC_DMODU_G_2F:
- check_insn(ctx, INSN_LOONGSON2F | ASE_LEXT);
- gen_loongson_integer(ctx, op1, rd, rs, rt);
- break;
#endif
default: /* Invalid */
MIPS_INVAL("special2_legacy");
@@ -13798,17 +13572,12 @@ static void decode_opc_special3_legacy(CPUMIPSState *env, DisasContext *ctx)
op1 = MASK_SPECIAL3(ctx->opcode);
switch (op1) {
- case OPC_DIV_G_2E:
- case OPC_DIVU_G_2E:
- case OPC_MOD_G_2E:
- case OPC_MODU_G_2E:
- case OPC_MULT_G_2E:
- case OPC_MULTU_G_2E:
+ case OPC_MUL_PH_DSP:
/*
- * OPC_MULT_G_2E, OPC_ADDUH_QB_DSP, OPC_MUL_PH_DSP have
+ * OPC_ADDUH_QB_DSP, OPC_MUL_PH_DSP have
* the same mask and op1.
*/
- if ((ctx->insn_flags & ASE_DSP_R2) && (op1 == OPC_MULT_G_2E)) {
+ if ((ctx->insn_flags & ASE_DSP_R2) && (op1 == OPC_MUL_PH_DSP)) {
op2 = MASK_ADDUH_QB(ctx->opcode);
switch (op2) {
case OPC_ADDUH_QB:
@@ -13836,8 +13605,6 @@ static void decode_opc_special3_legacy(CPUMIPSState *env, DisasContext *ctx)
gen_reserved_instruction(ctx);
break;
}
- } else if (ctx->insn_flags & INSN_LOONGSON2E) {
- gen_loongson_integer(ctx, op1, rd, rs, rt);
} else {
gen_reserved_instruction(ctx);
}
@@ -14066,15 +13833,6 @@ static void decode_opc_special3_legacy(CPUMIPSState *env, DisasContext *ctx)
}
break;
#if defined(TARGET_MIPS64)
- case OPC_DDIV_G_2E:
- case OPC_DDIVU_G_2E:
- case OPC_DMULT_G_2E:
- case OPC_DMULTU_G_2E:
- case OPC_DMOD_G_2E:
- case OPC_DMODU_G_2E:
- check_insn(ctx, INSN_LOONGSON2E);
- gen_loongson_integer(ctx, op1, rd, rs, rt);
- break;
case OPC_ABSQ_S_QH_DSP:
op2 = MASK_ABSQ_S_QH(ctx->opcode);
switch (op2) {
@@ -14952,7 +14710,9 @@ static bool decode_opc_legacy(CPUMIPSState *env, DisasContext *ctx)
} else {
/* OPC_BC1ANY2 */
check_cop1x(ctx);
- check_insn(ctx, ASE_MIPS3D);
+ if (!ase_3d_available(env)) {
+ return false;
+ }
gen_compute_branch1(ctx, MASK_BC1(ctx->opcode),
(rt >> 2) & 0x7, imm << 2);
}
@@ -14967,7 +14727,9 @@ static bool decode_opc_legacy(CPUMIPSState *env, DisasContext *ctx)
check_cp1_enabled(ctx);
check_insn_opc_removed(ctx, ISA_MIPS_R6);
check_cop1x(ctx);
- check_insn(ctx, ASE_MIPS3D);
+ if (!ase_3d_available(env)) {
+ return false;
+ }
/* fall through */
case OPC_BC1:
check_cp1_enabled(ctx);
@@ -15267,6 +15029,9 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx)
if (cpu_supports_isa(env, INSN_VR54XX) && decode_ext_vr54xx(ctx, ctx->opcode)) {
return;
}
+ if (TARGET_LONG_BITS == 64 && decode_ext_loongson(ctx, ctx->opcode)) {
+ return;
+ }
#if defined(TARGET_MIPS64)
if (ase_lcsr_available(env) && decode_ase_lcsr(ctx, ctx->opcode)) {
return;
diff --git a/target/mips/tcg/translate.h b/target/mips/tcg/translate.h
index 5d196e69ac..1bf153d183 100644
--- a/target/mips/tcg/translate.h
+++ b/target/mips/tcg/translate.h
@@ -217,10 +217,13 @@ void msa_translate_init(void);
void mxu_translate_init(void);
bool decode_ase_mxu(DisasContext *ctx, uint32_t insn);
+bool decode_64bit_enabled(DisasContext *ctx);
+
/* 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);
+bool decode_ext_loongson(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);
@@ -228,6 +231,11 @@ bool decode_ext_octeon(DisasContext *ctx, uint32_t insn);
#endif
bool decode_ext_vr54xx(DisasContext *ctx, uint32_t insn);
+static inline bool disas_mt_available(DisasContext *ctx)
+{
+ return ctx->CP0_Config3 & (1 << CP0C3_MT);
+}
+
/*
* Helpers for implementing sets of trans_* functions.
* Defer the implementation of NAME to FUNC, with optional extra arguments.