diff options
Diffstat (limited to 'arch/mips/math-emu')
-rw-r--r-- | arch/mips/math-emu/cp1emu.c | 106 |
1 files changed, 91 insertions, 15 deletions
diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index 7aa42b2caf89..8034ee4c3341 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -64,11 +64,14 @@ static int fpux_emu(struct pt_regs *, /* Control registers */ #define FPCREG_RID 0 /* $0 = revision id */ +#define FPCREG_FCCR 25 /* $25 = fccr */ +#define FPCREG_FEXR 26 /* $26 = fexr */ +#define FPCREG_FENR 28 /* $28 = fenr */ #define FPCREG_CSR 31 /* $31 = csr */ /* convert condition code register number to csr bit */ const unsigned int fpucondbit[8] = { - FPU_CSR_COND0, + FPU_CSR_COND, FPU_CSR_COND1, FPU_CSR_COND2, FPU_CSR_COND3, @@ -846,17 +849,53 @@ do { \ static inline void cop1_cfc(struct pt_regs *xcp, struct mips_fpu_struct *ctx, mips_instruction ir) { - u32 value; + u32 fcr31 = ctx->fcr31; + u32 value = 0; - if (MIPSInst_RD(ir) == FPCREG_CSR) { - value = ctx->fcr31; + switch (MIPSInst_RD(ir)) { + case FPCREG_CSR: + value = fcr31; pr_debug("%p gpr[%d]<-csr=%08x\n", - (void *)xcp->cp0_epc, - MIPSInst_RT(ir), value); - } else if (MIPSInst_RD(ir) == FPCREG_RID) + (void *)xcp->cp0_epc, MIPSInst_RT(ir), value); + break; + + case FPCREG_FENR: + if (!cpu_has_mips_r) + break; + value = (fcr31 >> (FPU_CSR_FS_S - MIPS_FENR_FS_S)) & + MIPS_FENR_FS; + value |= fcr31 & (FPU_CSR_ALL_E | FPU_CSR_RM); + pr_debug("%p gpr[%d]<-enr=%08x\n", + (void *)xcp->cp0_epc, MIPSInst_RT(ir), value); + break; + + case FPCREG_FEXR: + if (!cpu_has_mips_r) + break; + value = fcr31 & (FPU_CSR_ALL_X | FPU_CSR_ALL_S); + pr_debug("%p gpr[%d]<-exr=%08x\n", + (void *)xcp->cp0_epc, MIPSInst_RT(ir), value); + break; + + case FPCREG_FCCR: + if (!cpu_has_mips_r) + break; + value = (fcr31 >> (FPU_CSR_COND_S - MIPS_FCCR_COND0_S)) & + MIPS_FCCR_COND0; + value |= (fcr31 >> (FPU_CSR_COND1_S - MIPS_FCCR_COND1_S)) & + (MIPS_FCCR_CONDX & ~MIPS_FCCR_COND0); + pr_debug("%p gpr[%d]<-ccr=%08x\n", + (void *)xcp->cp0_epc, MIPSInst_RT(ir), value); + break; + + case FPCREG_RID: value = current_cpu_data.fpu_id; - else - value = 0; + break; + + default: + break; + } + if (MIPSInst_RT(ir)) xcp->regs[MIPSInst_RT(ir)] = value; } @@ -867,6 +906,7 @@ static inline void cop1_cfc(struct pt_regs *xcp, struct mips_fpu_struct *ctx, static inline void cop1_ctc(struct pt_regs *xcp, struct mips_fpu_struct *ctx, mips_instruction ir) { + u32 fcr31 = ctx->fcr31; u32 value; if (MIPSInst_RT(ir) == 0) @@ -874,16 +914,52 @@ static inline void cop1_ctc(struct pt_regs *xcp, struct mips_fpu_struct *ctx, else value = xcp->regs[MIPSInst_RT(ir)]; - /* we only have one writable control reg - */ - if (MIPSInst_RD(ir) == FPCREG_CSR) { + switch (MIPSInst_RD(ir)) { + case FPCREG_CSR: pr_debug("%p gpr[%d]->csr=%08x\n", - (void *)xcp->cp0_epc, - MIPSInst_RT(ir), value); + (void *)xcp->cp0_epc, MIPSInst_RT(ir), value); /* Don't write reserved bits. */ - ctx->fcr31 = value & ~FPU_CSR_RSVD; + fcr31 = value & ~FPU_CSR_RSVD; + break; + + case FPCREG_FENR: + if (!cpu_has_mips_r) + break; + pr_debug("%p gpr[%d]->enr=%08x\n", + (void *)xcp->cp0_epc, MIPSInst_RT(ir), value); + fcr31 &= ~(FPU_CSR_FS | FPU_CSR_ALL_E | FPU_CSR_RM); + fcr31 |= (value << (FPU_CSR_FS_S - MIPS_FENR_FS_S)) & + FPU_CSR_FS; + fcr31 |= value & (FPU_CSR_ALL_E | FPU_CSR_RM); + break; + + case FPCREG_FEXR: + if (!cpu_has_mips_r) + break; + pr_debug("%p gpr[%d]->exr=%08x\n", + (void *)xcp->cp0_epc, MIPSInst_RT(ir), value); + fcr31 &= ~(FPU_CSR_ALL_X | FPU_CSR_ALL_S); + fcr31 |= value & (FPU_CSR_ALL_X | FPU_CSR_ALL_S); + break; + + case FPCREG_FCCR: + if (!cpu_has_mips_r) + break; + pr_debug("%p gpr[%d]->ccr=%08x\n", + (void *)xcp->cp0_epc, MIPSInst_RT(ir), value); + fcr31 &= ~(FPU_CSR_CONDX | FPU_CSR_COND); + fcr31 |= (value << (FPU_CSR_COND_S - MIPS_FCCR_COND0_S)) & + FPU_CSR_COND; + fcr31 |= (value << (FPU_CSR_COND1_S - MIPS_FCCR_COND1_S)) & + FPU_CSR_CONDX; + break; + + default: + break; } + + ctx->fcr31 = fcr31; } /* |