aboutsummaryrefslogtreecommitdiff
path: root/target-mips
diff options
context:
space:
mode:
authorths <ths@c046a42c-6fe2-441c-8c8c-71466251a162>2007-12-25 20:46:56 +0000
committerths <ths@c046a42c-6fe2-441c-8c8c-71466251a162>2007-12-25 20:46:56 +0000
commite9c71dd1c1f5aeb3732261a02dcfae031973f053 (patch)
treede9b88fe2a6e0ffbb6b2f1fa63f401e14aa66e6a /target-mips
parent29fe0e3490ef63f564f426fc526d4415f44e7052 (diff)
Support for VR5432, and some of its special instructions. Original patch
by Dirk Behme. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3859 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'target-mips')
-rw-r--r--target-mips/exec.h14
-rw-r--r--target-mips/mips-defs.h14
-rw-r--r--target-mips/op.c182
-rw-r--r--target-mips/op_helper.c85
-rw-r--r--target-mips/translate.c101
-rw-r--r--target-mips/translate_init.c16
6 files changed, 405 insertions, 7 deletions
diff --git a/target-mips/exec.h b/target-mips/exec.h
index 307049ed31..7b2c4687f6 100644
--- a/target-mips/exec.h
+++ b/target-mips/exec.h
@@ -79,6 +79,20 @@ void do_madd (void);
void do_maddu (void);
void do_msub (void);
void do_msubu (void);
+void do_muls (void);
+void do_mulsu (void);
+void do_macc (void);
+void do_macchi (void);
+void do_maccu (void);
+void do_macchiu (void);
+void do_msac (void);
+void do_msachi (void);
+void do_msacu (void);
+void do_msachiu (void);
+void do_mulhi (void);
+void do_mulhiu (void);
+void do_mulshi (void);
+void do_mulshiu (void);
#endif
#if defined(TARGET_MIPS64)
void do_ddiv (void);
diff --git a/target-mips/mips-defs.h b/target-mips/mips-defs.h
index 76ea8d019b..2d0c1383dd 100644
--- a/target-mips/mips-defs.h
+++ b/target-mips/mips-defs.h
@@ -4,7 +4,7 @@
/* If we want to use host float regs... */
//#define USE_HOST_FLOAT_REGS
-/* real pages are variable size... */
+/* Real pages are variable size... */
#define TARGET_PAGE_BITS 12
#define MIPS_TLB_MAX 128
@@ -29,7 +29,7 @@
#define ISA_MIPS64 0x00000080
#define ISA_MIPS64R2 0x00000100
-/* MIPS ASE */
+/* MIPS ASEs. */
#define ASE_MIPS16 0x00001000
#define ASE_MIPS3D 0x00002000
#define ASE_MDMX 0x00004000
@@ -38,19 +38,23 @@
#define ASE_MT 0x00020000
#define ASE_SMARTMIPS 0x00040000
-/* Chip specific instructions. */
-/* Currently void */
+/* Chip specific instructions. */
+#define INSN_VR54XX 0x80000000
-/* MIPS CPU defines. */
+/* MIPS CPU defines. */
#define CPU_MIPS1 (ISA_MIPS1)
#define CPU_MIPS2 (CPU_MIPS1 | ISA_MIPS2)
#define CPU_MIPS3 (CPU_MIPS2 | ISA_MIPS3)
#define CPU_MIPS4 (CPU_MIPS3 | ISA_MIPS4)
+#define CPU_VR54XX (CPU_MIPS4 | INSN_VR54XX)
+
#define CPU_MIPS5 (CPU_MIPS4 | ISA_MIPS5)
+/* MIPS Technologies "Release 1" */
#define CPU_MIPS32 (CPU_MIPS2 | ISA_MIPS32)
#define CPU_MIPS64 (CPU_MIPS5 | CPU_MIPS32 | ISA_MIPS64)
+/* MIPS Technologies "Release 2" */
#define CPU_MIPS32R2 (CPU_MIPS32 | ISA_MIPS32R2)
#define CPU_MIPS64R2 (CPU_MIPS64 | CPU_MIPS32R2 | ISA_MIPS64R2)
diff --git a/target-mips/op.c b/target-mips/op.c
index b5c24b2316..cf965fa874 100644
--- a/target-mips/op.c
+++ b/target-mips/op.c
@@ -781,6 +781,90 @@ void op_msubu (void)
FORCE_RET();
}
+/* Multiplication variants of the vr54xx. */
+void op_muls (void)
+{
+ CALL_FROM_TB0(do_muls);
+ FORCE_RET();
+}
+
+void op_mulsu (void)
+{
+ CALL_FROM_TB0(do_mulsu);
+ FORCE_RET();
+}
+
+void op_macc (void)
+{
+ CALL_FROM_TB0(do_macc);
+ FORCE_RET();
+}
+
+void op_macchi (void)
+{
+ CALL_FROM_TB0(do_macchi);
+ FORCE_RET();
+}
+
+void op_maccu (void)
+{
+ CALL_FROM_TB0(do_maccu);
+ FORCE_RET();
+}
+void op_macchiu (void)
+{
+ CALL_FROM_TB0(do_macchiu);
+ FORCE_RET();
+}
+
+void op_msac (void)
+{
+ CALL_FROM_TB0(do_msac);
+ FORCE_RET();
+}
+
+void op_msachi (void)
+{
+ CALL_FROM_TB0(do_msachi);
+ FORCE_RET();
+}
+
+void op_msacu (void)
+{
+ CALL_FROM_TB0(do_msacu);
+ FORCE_RET();
+}
+
+void op_msachiu (void)
+{
+ CALL_FROM_TB0(do_msachiu);
+ FORCE_RET();
+}
+
+void op_mulhi (void)
+{
+ CALL_FROM_TB0(do_mulhi);
+ FORCE_RET();
+}
+
+void op_mulhiu (void)
+{
+ CALL_FROM_TB0(do_mulhiu);
+ FORCE_RET();
+}
+
+void op_mulshi (void)
+{
+ CALL_FROM_TB0(do_mulshi);
+ FORCE_RET();
+}
+
+void op_mulshiu (void)
+{
+ CALL_FROM_TB0(do_mulshiu);
+ FORCE_RET();
+}
+
#else /* TARGET_LONG_BITS > HOST_LONG_BITS */
static always_inline uint64_t get_HILO (void)
@@ -795,6 +879,18 @@ static always_inline void set_HILO (uint64_t HILO)
env->HI[0][env->current_tc] = (int32_t)(HILO >> 32);
}
+static always_inline void set_HIT0_LO (uint64_t HILO)
+{
+ env->LO[0][env->current_tc] = (int32_t)(HILO & 0xFFFFFFFF);
+ T0 = env->HI[0][env->current_tc] = (int32_t)(HILO >> 32);
+}
+
+static always_inline void set_HI_LOT0 (uint64_t HILO)
+{
+ T0 = env->LO[0][env->current_tc] = (int32_t)(HILO & 0xFFFFFFFF);
+ env->HI[0][env->current_tc] = (int32_t)(HILO >> 32);
+}
+
void op_mult (void)
{
set_HILO((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
@@ -842,6 +938,92 @@ void op_msubu (void)
set_HILO(get_HILO() - tmp);
FORCE_RET();
}
+
+/* Multiplication variants of the vr54xx. */
+void op_muls (void)
+{
+ set_HI_LOT0(0 - ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1));
+ FORCE_RET();
+}
+
+void op_mulsu (void)
+{
+ set_HI_LOT0(0 - ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1));
+ FORCE_RET();
+}
+
+void op_macc (void)
+{
+ set_HI_LOT0(get_HILO() + ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1));
+ FORCE_RET();
+}
+
+void op_macchi (void)
+{
+ set_HIT0_LO(get_HILO() + ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1));
+ FORCE_RET();
+}
+
+void op_maccu (void)
+{
+ set_HI_LOT0(get_HILO() + ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1));
+ FORCE_RET();
+}
+
+void op_macchiu (void)
+{
+ set_HIT0_LO(get_HILO() + ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1));
+ FORCE_RET();
+}
+
+void op_msac (void)
+{
+ set_HI_LOT0(get_HILO() - ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1));
+ FORCE_RET();
+}
+
+void op_msachi (void)
+{
+ set_HIT0_LO(get_HILO() - ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1));
+ FORCE_RET();
+}
+
+void op_msacu (void)
+{
+ set_HI_LOT0(get_HILO() - ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1));
+ FORCE_RET();
+}
+
+void op_msachiu (void)
+{
+ set_HIT0_LO(get_HILO() - ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1));
+ FORCE_RET();
+}
+
+void op_mulhi (void)
+{
+ set_HIT0_LO((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
+ FORCE_RET();
+}
+
+void op_mulhiu (void)
+{
+ set_HIT0_LO((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1);
+ FORCE_RET();
+}
+
+void op_mulshi (void)
+{
+ set_HIT0_LO(0 - ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1));
+ FORCE_RET();
+}
+
+void op_mulshiu (void)
+{
+ set_HIT0_LO(0 - ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1));
+ FORCE_RET();
+}
+
#endif /* TARGET_LONG_BITS > HOST_LONG_BITS */
#if defined(TARGET_MIPS64)
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index 36c4b73f93..93ba79c7e4 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -172,6 +172,18 @@ static always_inline void set_HILO (uint64_t HILO)
env->HI[0][env->current_tc] = (int32_t)(HILO >> 32);
}
+static always_inline void set_HIT0_LO (uint64_t HILO)
+{
+ env->LO[0][env->current_tc] = (int32_t)(HILO & 0xFFFFFFFF);
+ T0 = env->HI[0][env->current_tc] = (int32_t)(HILO >> 32);
+}
+
+static always_inline void set_HI_LOT0 (uint64_t HILO)
+{
+ T0 = env->LO[0][env->current_tc] = (int32_t)(HILO & 0xFFFFFFFF);
+ env->HI[0][env->current_tc] = (int32_t)(HILO >> 32);
+}
+
void do_mult (void)
{
set_HILO((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
@@ -213,7 +225,78 @@ void do_msubu (void)
tmp = ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1);
set_HILO(get_HILO() - tmp);
}
-#endif
+
+/* Multiplication variants of the vr54xx. */
+void do_muls (void)
+{
+ set_HI_LOT0(0 - ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1));
+}
+
+void do_mulsu (void)
+{
+ set_HI_LOT0(0 - ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1));
+}
+
+void do_macc (void)
+{
+ set_HI_LOT0(((int64_t)get_HILO()) + ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1));
+}
+
+void do_macchi (void)
+{
+ set_HIT0_LO(((int64_t)get_HILO()) + ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1));
+}
+
+void do_maccu (void)
+{
+ set_HI_LOT0(((uint64_t)get_HILO()) + ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1));
+}
+
+void do_macchiu (void)
+{
+ set_HIT0_LO(((uint64_t)get_HILO()) + ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1));
+}
+
+void do_msac (void)
+{
+ set_HI_LOT0(((int64_t)get_HILO()) - ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1));
+}
+
+void do_msachi (void)
+{
+ set_HIT0_LO(((int64_t)get_HILO()) - ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1));
+}
+
+void do_msacu (void)
+{
+ set_HI_LOT0(((uint64_t)get_HILO()) - ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1));
+}
+
+void do_msachiu (void)
+{
+ set_HIT0_LO(((uint64_t)get_HILO()) - ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1));
+}
+
+void do_mulhi (void)
+{
+ set_HIT0_LO((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
+}
+
+void do_mulhiu (void)
+{
+ set_HIT0_LO((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1);
+}
+
+void do_mulshi (void)
+{
+ set_HIT0_LO(0 - ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1));
+}
+
+void do_mulshiu (void)
+{
+ set_HIT0_LO(0 - ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1));
+}
+#endif /* TARGET_LONG_BITS > HOST_LONG_BITS */
#if HOST_LONG_BITS < 64
void do_div (void)
diff --git a/target-mips/translate.c b/target-mips/translate.c
index be29357f10..1d8aea185b 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -214,6 +214,26 @@ enum {
OPC_SPECIAL3D_RESERVED = 0x3D | OPC_SPECIAL,
};
+/* Multiplication variants of the vr54xx. */
+#define MASK_MUL_VR54XX(op) MASK_SPECIAL(op) | (op & (0x1F << 6))
+
+enum {
+ OPC_VR54XX_MULS = (0x03 << 6) | OPC_MULT,
+ OPC_VR54XX_MULSU = (0x03 << 6) | OPC_MULTU,
+ OPC_VR54XX_MACC = (0x05 << 6) | OPC_MULT,
+ OPC_VR54XX_MACCU = (0x05 << 6) | OPC_MULTU,
+ OPC_VR54XX_MSAC = (0x07 << 6) | OPC_MULT,
+ OPC_VR54XX_MSACU = (0x07 << 6) | OPC_MULTU,
+ OPC_VR54XX_MULHI = (0x09 << 6) | OPC_MULT,
+ OPC_VR54XX_MULHIU = (0x09 << 6) | OPC_MULTU,
+ OPC_VR54XX_MULSHI = (0x0B << 6) | OPC_MULT,
+ OPC_VR54XX_MULSHIU = (0x0B << 6) | OPC_MULTU,
+ OPC_VR54XX_MACCHI = (0x0D << 6) | OPC_MULT,
+ OPC_VR54XX_MACCHIU = (0x0D << 6) | OPC_MULTU,
+ OPC_VR54XX_MSACHI = (0x0F << 6) | OPC_MULT,
+ OPC_VR54XX_MSACHIU = (0x0F << 6) | OPC_MULTU,
+};
+
/* REGIMM (rt field) opcodes */
#define MASK_REGIMM(op) MASK_OP_MAJOR(op) | (op & (0x1F << 16))
@@ -1530,6 +1550,80 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc,
MIPS_DEBUG("%s %s %s", opn, regnames[rs], regnames[rt]);
}
+static void gen_mul_vr54xx (DisasContext *ctx, uint32_t opc,
+ int rd, int rs, int rt)
+{
+ const char *opn = "mul vr54xx";
+
+ GEN_LOAD_REG_T0(rs);
+ GEN_LOAD_REG_T1(rt);
+
+ switch (opc) {
+ case OPC_VR54XX_MULS:
+ gen_op_muls();
+ opn = "muls";
+ break;
+ case OPC_VR54XX_MULSU:
+ gen_op_mulsu();
+ opn = "mulsu";
+ break;
+ case OPC_VR54XX_MACC:
+ gen_op_macc();
+ opn = "macc";
+ break;
+ case OPC_VR54XX_MACCU:
+ gen_op_maccu();
+ opn = "maccu";
+ break;
+ case OPC_VR54XX_MSAC:
+ gen_op_msac();
+ opn = "msac";
+ break;
+ case OPC_VR54XX_MSACU:
+ gen_op_msacu();
+ opn = "msacu";
+ break;
+ case OPC_VR54XX_MULHI:
+ gen_op_mulhi();
+ opn = "mulhi";
+ break;
+ case OPC_VR54XX_MULHIU:
+ gen_op_mulhiu();
+ opn = "mulhiu";
+ break;
+ case OPC_VR54XX_MULSHI:
+ gen_op_mulshi();
+ opn = "mulshi";
+ break;
+ case OPC_VR54XX_MULSHIU:
+ gen_op_mulshiu();
+ opn = "mulshiu";
+ break;
+ case OPC_VR54XX_MACCHI:
+ gen_op_macchi();
+ opn = "macchi";
+ break;
+ case OPC_VR54XX_MACCHIU:
+ gen_op_macchiu();
+ opn = "macchiu";
+ break;
+ case OPC_VR54XX_MSACHI:
+ gen_op_msachi();
+ opn = "msachi";
+ break;
+ case OPC_VR54XX_MSACHIU:
+ gen_op_msachiu();
+ opn = "msachiu";
+ break;
+ default:
+ MIPS_INVAL("mul vr54xx");
+ generate_exception(ctx, EXCP_RI);
+ return;
+ }
+ GEN_STORE_T0_REG(rd);
+ MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
+}
+
static void gen_cl (DisasContext *ctx, uint32_t opc,
int rd, int rs)
{
@@ -5973,7 +6067,12 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
gen_arith(env, ctx, op1, rd, rs, rt);
break;
case OPC_MULT ... OPC_DIVU:
- gen_muldiv(ctx, op1, rs, rt);
+ if (sa) {
+ check_insn(env, ctx, INSN_VR54XX);
+ op1 = MASK_MUL_VR54XX(ctx->opcode);
+ gen_mul_vr54xx(ctx, op1, rd, rs, rt);
+ } else
+ gen_muldiv(ctx, op1, rs, rt);
break;
case OPC_JR ... OPC_JALR:
gen_compute_branch(ctx, op1, rs, rd, sa);
diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c
index a2dec0af9f..57666d4db7 100644
--- a/target-mips/translate_init.c
+++ b/target-mips/translate_init.c
@@ -306,6 +306,22 @@ static mips_def_t mips_defs[] =
.mmu_type = MMU_TYPE_R4000,
},
{
+ .name = "VR5432",
+ .CP0_PRid = 0x00005400,
+ /* No L2 cache, icache size 8k, dcache size 8k, uncached coherency. */
+ .CP0_Config0 = (1 << 17) | (0x1 << 9) | (0x1 << 6) | (0x2 << CP0C0_K0),
+ .CP0_Config1 = (1 << CP0C1_FP) | (47 << CP0C1_MMU),
+ .SYNCI_Step = 16,
+ .CCRes = 2,
+ .CP0_Status_rw_bitmask = 0x3678FFFF,
+ /* The VR5432 has a full 64bit FPU but doesn't use the fcr0 bits. */
+ .CP1_fcr0 = (0x54 << FCR0_PRID) | (0x0 << FCR0_REV),
+ .SEGBITS = 40,
+ .PABITS = 32,
+ .insn_flags = CPU_VR54XX,
+ .mmu_type = MMU_TYPE_R4000,
+ },
+ {
.name = "5Kc",
.CP0_PRid = 0x00018100,
.CP0_Config0 = MIPS_CONFIG0 | (0x2 << CP0C0_AT) |