Commit f8c3c671 authored by Markos Chandras's avatar Markos Chandras Committed by Ralf Baechle

MIPS: math-emu: Add support for the CMP.condn.fmt R6 instruction

Add support for emulating the new CMP.condn.fmt R6 instructions and
return SIGILL for the old C.cond.fmt if R2 emulation is not enabled
since it's not supported by R6.

The functionality of the new CMP.condn.fmt is the following one:

If the comparison specified by the condn field of the instruction
is true for the operand values, the result is true; otherwise, the
result is false. If no exception is taken, the result is written into
FPR fd; true is all 1s and false is all 0s repeated the operand width
of fmt. All other bits beyond the operand width fmt are UNPREDICTABLE.
Signed-off-by: default avatarMarkos Chandras <markos.chandras@imgtec.com>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/10953/Signed-off-by: default avatarRalf Baechle <ralf@linux-mips.org>
parent 107d3400
......@@ -1394,6 +1394,14 @@ static const unsigned char cmptab[8] = {
IEEE754_CLT | IEEE754_CEQ | IEEE754_CUN, /* cmp_ule (sig) cmp_ngt */
};
static const unsigned char negative_cmptab[8] = {
0, /* Reserved */
IEEE754_CLT | IEEE754_CGT | IEEE754_CEQ,
IEEE754_CLT | IEEE754_CGT | IEEE754_CUN,
IEEE754_CLT | IEEE754_CGT,
/* Reserved */
};
/*
* Additional MIPS4 instructions
......@@ -1838,7 +1846,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
goto copcsr;
default:
if (MIPSInst_FUNC(ir) >= fcmp_op) {
if (!NO_R6EMU && MIPSInst_FUNC(ir) >= fcmp_op) {
unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op;
union ieee754sp fs, ft;
......@@ -2015,7 +2023,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
goto copcsr;
default:
if (MIPSInst_FUNC(ir) >= fcmp_op) {
if (!NO_R6EMU && MIPSInst_FUNC(ir) >= fcmp_op) {
unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op;
union ieee754dp fs, ft;
......@@ -2057,11 +2065,66 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
rv.d = ieee754dp_fint(fs.bits);
rfmt = d_fmt;
goto copcsr;
default: {
/* Emulating the new CMP.condn.fmt R6 instruction */
#define CMPOP_MASK 0x7
#define SIGN_BIT (0x1 << 3)
#define PREDICATE_BIT (0x1 << 4)
int cmpop = MIPSInst_FUNC(ir) & CMPOP_MASK;
int sig = MIPSInst_FUNC(ir) & SIGN_BIT;
union ieee754sp fs, ft;
/* This is an R6 only instruction */
if (!cpu_has_mips_r6 ||
(MIPSInst_FUNC(ir) & 0x20))
return SIGILL;
/* fmt is w_fmt for single precision so fix it */
rfmt = s_fmt;
/* default to false */
rv.w = 0;
/* CMP.condn.S */
SPFROMREG(fs, MIPSInst_FS(ir));
SPFROMREG(ft, MIPSInst_FT(ir));
/* positive predicates */
if (!(MIPSInst_FUNC(ir) & PREDICATE_BIT)) {
if (ieee754sp_cmp(fs, ft, cmptab[cmpop],
sig))
rv.w = -1; /* true, all 1s */
if ((sig) &&
ieee754_cxtest(IEEE754_INVALID_OPERATION))
rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S;
else
goto copcsr;
} else {
/* negative predicates */
switch (cmpop) {
case 1:
case 2:
case 3:
if (ieee754sp_cmp(fs, ft,
negative_cmptab[cmpop],
sig))
rv.w = -1; /* true, all 1s */
if (sig &&
ieee754_cxtest(IEEE754_INVALID_OPERATION))
rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S;
else
goto copcsr;
break;
default:
/* Reserved R6 ops */
pr_err("Reserved MIPS R6 CMP.condn.S operation\n");
return SIGILL;
}
}
break;
}
}
}
case l_fmt:
......@@ -2081,11 +2144,60 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
rv.d = ieee754dp_flong(bits);
rfmt = d_fmt;
goto copcsr;
default: {
/* Emulating the new CMP.condn.fmt R6 instruction */
int cmpop = MIPSInst_FUNC(ir) & CMPOP_MASK;
int sig = MIPSInst_FUNC(ir) & SIGN_BIT;
union ieee754dp fs, ft;
if (!cpu_has_mips_r6 ||
(MIPSInst_FUNC(ir) & 0x20))
return SIGILL;
/* fmt is l_fmt for double precision so fix it */
rfmt = d_fmt;
/* default to false */
rv.l = 0;
/* CMP.condn.D */
DPFROMREG(fs, MIPSInst_FS(ir));
DPFROMREG(ft, MIPSInst_FT(ir));
/* positive predicates */
if (!(MIPSInst_FUNC(ir) & PREDICATE_BIT)) {
if (ieee754dp_cmp(fs, ft,
cmptab[cmpop], sig))
rv.l = -1LL; /* true, all 1s */
if (sig &&
ieee754_cxtest(IEEE754_INVALID_OPERATION))
rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S;
else
goto copcsr;
} else {
/* negative predicates */
switch (cmpop) {
case 1:
case 2:
case 3:
if (ieee754dp_cmp(fs, ft,
negative_cmptab[cmpop],
sig))
rv.l = -1LL; /* true, all 1s */
if (sig &&
ieee754_cxtest(IEEE754_INVALID_OPERATION))
rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S;
else
goto copcsr;
break;
default:
/* Reserved R6 ops */
pr_err("Reserved MIPS R6 CMP.condn.D operation\n");
return SIGILL;
}
}
break;
}
}
default:
return SIGILL;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment