lol
1From bf55ef4e3c2f622ac013f196affbd11b67b59223 Mon Sep 17 00:00:00 2001
2From: Mark H Weaver <mhw@netris.org>
3Date: Fri, 28 Oct 2011 13:24:37 -0400
4Subject: [PATCH 2/4] Fix handling of prefx instruction in mips/math-emu
5
6* The instruction is named prefx, not pfetch, and its function
7 field is 0x17, not 0x07.
8
9* Recognize the prefx instruction regardless of what bits happen to be
10 in bits 21-25, which is the format field of the floating-point ops,
11 but holds the base register of the prefx instruction.
12---
13 arch/mips/include/asm/inst.h | 4 ++--
14 arch/mips/math-emu/cp1emu.c | 16 +++++++---------
15 2 files changed, 9 insertions(+), 11 deletions(-)
16
17diff --git a/arch/mips/include/asm/inst.h b/arch/mips/include/asm/inst.h
18index ab84064..3048edc 100644
19--- a/arch/mips/include/asm/inst.h
20+++ b/arch/mips/include/asm/inst.h
21@@ -161,8 +161,8 @@ enum cop1_sdw_func {
22 */
23 enum cop1x_func {
24 lwxc1_op = 0x00, ldxc1_op = 0x01,
25- pfetch_op = 0x07, swxc1_op = 0x08,
26- sdxc1_op = 0x09, madd_s_op = 0x20,
27+ swxc1_op = 0x08, sdxc1_op = 0x09,
28+ prefx_op = 0x17, madd_s_op = 0x20,
29 madd_d_op = 0x21, madd_e_op = 0x22,
30 msub_s_op = 0x28, msub_d_op = 0x29,
31 msub_e_op = 0x2a, nmadd_s_op = 0x30,
32diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c
33index dbf2f93..87ddba1 100644
34--- a/arch/mips/math-emu/cp1emu.c
35+++ b/arch/mips/math-emu/cp1emu.c
36@@ -739,7 +739,7 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
37 break;
38
39 default:
40- return SIGILL;
41+ goto SIGILL_unless_prefx_op;
42 }
43 break;
44 }
45@@ -809,19 +809,17 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
46 goto copcsr;
47
48 default:
49- return SIGILL;
50+ goto SIGILL_unless_prefx_op;
51 }
52 break;
53 }
54
55- case 0x7: /* 7 */
56- if (MIPSInst_FUNC(ir) != pfetch_op) {
57- return SIGILL;
58- }
59- /* ignore prefx operation */
60- break;
61-
62 default:
63+ SIGILL_unless_prefx_op:
64+ if (MIPSInst_FUNC(ir) == prefx_op) {
65+ /* ignore prefx operation */
66+ break;
67+ }
68 return SIGILL;
69 }
70
71--
721.7.5.4
73
74From 97a564e3eddbfb84844b8eccb3bd751c71dfb3eb Mon Sep 17 00:00:00 2001
75From: Mark H Weaver <mhw@netris.org>
76Date: Fri, 28 Oct 2011 13:35:27 -0400
77Subject: [PATCH 3/4] Don't process empty cause flags after simple fp move on
78 mips
79
80---
81 arch/mips/math-emu/cp1emu.c | 4 ++--
82 1 files changed, 2 insertions(+), 2 deletions(-)
83
84diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c
85index 87ddba1..fefcba2 100644
86--- a/arch/mips/math-emu/cp1emu.c
87+++ b/arch/mips/math-emu/cp1emu.c
88@@ -912,7 +912,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
89 case fmov_op:
90 /* an easy one */
91 SPFROMREG(rv.s, MIPSInst_FS(ir));
92- goto copcsr;
93+ break;
94
95 /* binary op on handler */
96 scopbop:
97@@ -1099,7 +1099,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
98 case fmov_op:
99 /* an easy one */
100 DPFROMREG(rv.d, MIPSInst_FS(ir));
101- goto copcsr;
102+ break;
103
104 /* binary op on handler */
105 dcopbop:{
106--
1071.7.5.4
108
109From 4051727b3007ef3675e7258ed86fa8517f86d929 Mon Sep 17 00:00:00 2001
110From: Mark H Weaver <mhw@netris.org>
111Date: Fri, 28 Oct 2011 13:39:10 -0400
112Subject: [PATCH 4/4] Support Loongson2f floating-point instructions in
113 mips/math-emu
114
115* (arch/mips/include/asm/inst.h): Add Loongson2f function field values
116 for madd/msub/nmadd/nmsub that use the spec2 opcode, and the
117 Loongson2f/MIPS-5 format field value for paired-single
118 floating-point operations.
119
120* (arch/mips/math-emu/cp1emu.c): Add support for the Loongson2f
121 instructions for madd/msub/nmadd/nmsub, which use the spec2 opcode.
122 Also add support for the Loongson2f instructions that use the
123 paired-single floating-point format.
124---
125 arch/mips/include/asm/inst.h | 4 +-
126 arch/mips/math-emu/cp1emu.c | 287 +++++++++++++++++++++++++++++++++++++++++-
127 2 files changed, 289 insertions(+), 2 deletions(-)
128
129diff --git a/arch/mips/include/asm/inst.h b/arch/mips/include/asm/inst.h
130index 3048edc..0e8ba7c 100644
131--- a/arch/mips/include/asm/inst.h
132+++ b/arch/mips/include/asm/inst.h
133@@ -61,6 +61,8 @@ enum spec_op {
134 enum spec2_op {
135 madd_op, maddu_op, mul_op, spec2_3_unused_op,
136 msub_op, msubu_op, /* more unused ops */
137+ loongson_madd_op = 0x18, loongson_msub_op,
138+ loongson_nmadd_op, loongson_nmsub_op,
139 clz_op = 0x20, clo_op,
140 dclz_op = 0x24, dclo_op,
141 sdbpp_op = 0x3f
142@@ -133,7 +135,7 @@ enum cop0_com_func {
143 */
144 enum cop1_fmt {
145 s_fmt, d_fmt, e_fmt, q_fmt,
146- w_fmt, l_fmt
147+ w_fmt, l_fmt, ps_fmt
148 };
149
150 /*
151diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c
152index fefcba2..166b2a4 100644
153--- a/arch/mips/math-emu/cp1emu.c
154+++ b/arch/mips/math-emu/cp1emu.c
155@@ -7,6 +7,9 @@
156 * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
157 * Copyright (C) 2000 MIPS Technologies, Inc.
158 *
159+ * Loongson instruction support
160+ * Copyright (C) 2011 Mark H Weaver <mhw@netris.org>
161+ *
162 * This program is free software; you can distribute it and/or modify it
163 * under the terms of the GNU General Public License (Version 2) as
164 * published by the Free Software Foundation.
165@@ -57,6 +60,14 @@
166 #endif
167 #define __mips 4
168
169+#ifdef __loongson_fp
170+#undef __loongson_fp
171+#endif
172+#if __mips >= 4 && __mips != 32
173+/* Include support for Loongson floating point instructions */
174+#define __loongson_fp 1
175+#endif
176+
177 /* Function which emulates a floating point instruction. */
178
179 static int fpu_emu(struct pt_regs *, struct mips_fpu_struct *,
180@@ -66,6 +77,10 @@ static int fpu_emu(struct pt_regs *, struct mips_fpu_struct *,
181 static int fpux_emu(struct pt_regs *,
182 struct mips_fpu_struct *, mips_instruction, void *__user *);
183 #endif
184+#ifdef __loongson_fp
185+static int loongson_spec2_emu(struct pt_regs *,
186+ struct mips_fpu_struct *, mips_instruction, void *__user *);
187+#endif
188
189 /* Further private data for which no space exists in mips_fpu_struct */
190
191@@ -203,6 +218,14 @@ static inline int cop1_64bit(struct pt_regs *xcp)
192 #define DPFROMREG(dp, x) DIFROMREG((dp).bits, x)
193 #define DPTOREG(dp, x) DITOREG((dp).bits, x)
194
195+/* Support for Loongson paired single floating-point format */
196+#define PSIFROMREG(si1, si2, x) ({ u64 di; DIFROMREG(di, x); \
197+ (si1) = (u32)di; (si2) = (u32)(di >> 32); })
198+#define PSITOREG(si1, si2, x) DITOREG((si1) | ((u64)(si2) << 32), x)
199+
200+#define PSPFROMREG(sp1, sp2, x) PSIFROMREG((sp1).bits, (sp2).bits, x)
201+#define PSPTOREG(sp1, sp2, x) PSITOREG((sp1).bits, (sp2).bits, x)
202+
203 /*
204 * Emulate the single floating point instruction pointed at by EPC.
205 * Two instructions if the instruction is in a branch delay slot.
206@@ -568,6 +591,15 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
207 break;
208 #endif
209
210+#ifdef __loongson_fp
211+ case spec2_op:{
212+ int sig = loongson_spec2_emu(xcp, ctx, ir, fault_addr);
213+ if (sig)
214+ return sig;
215+ break;
216+ }
217+#endif
218+
219 default:
220 return SIGILL;
221 }
222@@ -646,6 +678,172 @@ DEF3OP(msub, dp, ieee754dp_mul, ieee754dp_sub, );
223 DEF3OP(nmadd, dp, ieee754dp_mul, ieee754dp_add, ieee754dp_neg);
224 DEF3OP(nmsub, dp, ieee754dp_mul, ieee754dp_sub, ieee754dp_neg);
225
226+#ifdef __loongson_fp
227+static int loongson_spec2_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
228+ mips_instruction ir, void *__user *fault_addr)
229+{
230+ int rfmt; /* resulting format */
231+ unsigned rcsr = 0; /* resulting csr */
232+ union {
233+ ieee754dp d;
234+ struct {
235+ ieee754sp s;
236+ ieee754sp s2;
237+ };
238+ } rv; /* resulting value */
239+
240+ /* XXX maybe add a counter for loongson spec2 fp instructions? */
241+ /* MIPS_FPU_EMU_INC_STATS(cp1xops); */
242+
243+ switch (rfmt = (MIPSInst_FFMT(ir) & 0xf)) {
244+ case s_fmt:{
245+ ieee754sp(*handler) (ieee754sp, ieee754sp, ieee754sp);
246+ ieee754sp fd, fs, ft;
247+
248+ switch (MIPSInst_FUNC(ir)) {
249+ case loongson_madd_op:
250+ handler = fpemu_sp_madd;
251+ goto scoptop;
252+ case loongson_msub_op:
253+ handler = fpemu_sp_msub;
254+ goto scoptop;
255+ case loongson_nmadd_op:
256+ handler = fpemu_sp_nmadd;
257+ goto scoptop;
258+ case loongson_nmsub_op:
259+ handler = fpemu_sp_nmsub;
260+ goto scoptop;
261+
262+ scoptop:
263+ SPFROMREG(fd, MIPSInst_FD(ir));
264+ SPFROMREG(fs, MIPSInst_FS(ir));
265+ SPFROMREG(ft, MIPSInst_FT(ir));
266+ rv.s = (*handler) (fd, fs, ft);
267+
268+ copcsr:
269+ if (ieee754_cxtest(IEEE754_INEXACT))
270+ rcsr |= FPU_CSR_INE_X | FPU_CSR_INE_S;
271+ if (ieee754_cxtest(IEEE754_UNDERFLOW))
272+ rcsr |= FPU_CSR_UDF_X | FPU_CSR_UDF_S;
273+ if (ieee754_cxtest(IEEE754_OVERFLOW))
274+ rcsr |= FPU_CSR_OVF_X | FPU_CSR_OVF_S;
275+ if (ieee754_cxtest(IEEE754_INVALID_OPERATION))
276+ rcsr |= FPU_CSR_INV_X | FPU_CSR_INV_S;
277+
278+ break;
279+
280+ default:
281+ return SIGILL;
282+ }
283+ break;
284+ }
285+
286+ case d_fmt:{
287+ ieee754dp(*handler) (ieee754dp, ieee754dp, ieee754dp);
288+ ieee754dp fd, fs, ft;
289+
290+ switch (MIPSInst_FUNC(ir)) {
291+ case loongson_madd_op:
292+ handler = fpemu_dp_madd;
293+ goto dcoptop;
294+ case loongson_msub_op:
295+ handler = fpemu_dp_msub;
296+ goto dcoptop;
297+ case loongson_nmadd_op:
298+ handler = fpemu_dp_nmadd;
299+ goto dcoptop;
300+ case loongson_nmsub_op:
301+ handler = fpemu_dp_nmsub;
302+ goto dcoptop;
303+
304+ dcoptop:
305+ DPFROMREG(fd, MIPSInst_FD(ir));
306+ DPFROMREG(fs, MIPSInst_FS(ir));
307+ DPFROMREG(ft, MIPSInst_FT(ir));
308+ rv.d = (*handler) (fd, fs, ft);
309+ goto copcsr;
310+
311+ default:
312+ return SIGILL;
313+ }
314+ break;
315+ }
316+
317+ case ps_fmt:{
318+ ieee754sp(*handler) (ieee754sp, ieee754sp, ieee754sp);
319+ struct _ieee754_csr ieee754_csr_save;
320+ ieee754sp fd1, fs1, ft1;
321+ ieee754sp fd2, fs2, ft2;
322+
323+ switch (MIPSInst_FUNC(ir)) {
324+ case loongson_madd_op:
325+ handler = fpemu_sp_madd;
326+ goto pscoptop;
327+ case loongson_msub_op:
328+ handler = fpemu_sp_msub;
329+ goto pscoptop;
330+ case loongson_nmadd_op:
331+ handler = fpemu_sp_nmadd;
332+ goto pscoptop;
333+ case loongson_nmsub_op:
334+ handler = fpemu_sp_nmsub;
335+ goto pscoptop;
336+
337+ pscoptop:
338+ PSPFROMREG(fd1, fd2, MIPSInst_FD(ir));
339+ PSPFROMREG(fs1, fs2, MIPSInst_FS(ir));
340+ PSPFROMREG(ft1, ft2, MIPSInst_FT(ir));
341+ rv.s = (*handler) (fd1, fs1, ft1);
342+ ieee754_csr_save = ieee754_csr;
343+ rv.s2 = (*handler) (fd2, fs2, ft2);
344+ ieee754_csr.cx |= ieee754_csr_save.cx;
345+ ieee754_csr.sx |= ieee754_csr_save.sx;
346+ goto copcsr;
347+
348+ default:
349+ return SIGILL;
350+ }
351+ break;
352+ }
353+
354+ default:
355+ return SIGILL;
356+ }
357+
358+ /*
359+ * Update the fpu CSR register for this operation.
360+ * If an exception is required, generate a tidy SIGFPE exception,
361+ * without updating the result register.
362+ * Note: cause exception bits do not accumulate, they are rewritten
363+ * for each op; only the flag/sticky bits accumulate.
364+ */
365+ ctx->fcr31 = (ctx->fcr31 & ~FPU_CSR_ALL_X) | rcsr;
366+ if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) {
367+ /*printk ("SIGFPE: fpu csr = %08x\n",ctx->fcr31); */
368+ return SIGFPE;
369+ }
370+
371+ /*
372+ * Now we can safely write the result back to the register file.
373+ */
374+ switch (rfmt) {
375+ case d_fmt:
376+ DPTOREG(rv.d, MIPSInst_FD(ir));
377+ break;
378+ case s_fmt:
379+ SPTOREG(rv.s, MIPSInst_FD(ir));
380+ break;
381+ case ps_fmt:
382+ PSPTOREG(rv.s, rv.s2, MIPSInst_FD(ir));
383+ break;
384+ default:
385+ return SIGILL;
386+ }
387+
388+ return 0;
389+}
390+#endif
391+
392 static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
393 mips_instruction ir, void *__user *fault_addr)
394 {
395@@ -840,7 +1038,12 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
396 unsigned cond;
397 union {
398 ieee754dp d;
399- ieee754sp s;
400+ struct {
401+ ieee754sp s;
402+#ifdef __loongson_fp
403+ ieee754sp s2; /* for Loongson paired singles */
404+#endif
405+ };
406 int w;
407 #ifdef __mips64
408 s64 l;
409@@ -1210,6 +1413,83 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
410 break;
411 }
412
413+#ifdef __loongson_fp
414+ case ps_fmt:{ /* 6 */
415+ /* Support for Loongson paired single fp instructions */
416+ union {
417+ ieee754sp(*b) (ieee754sp, ieee754sp);
418+ ieee754sp(*u) (ieee754sp);
419+ } handler;
420+
421+ switch (MIPSInst_FUNC(ir)) {
422+ /* binary ops */
423+ case fadd_op:
424+ handler.b = ieee754sp_add;
425+ goto pscopbop;
426+ case fsub_op:
427+ handler.b = ieee754sp_sub;
428+ goto pscopbop;
429+ case fmul_op:
430+ handler.b = ieee754sp_mul;
431+ goto pscopbop;
432+
433+ /* unary ops */
434+ case fabs_op:
435+ handler.u = ieee754sp_abs;
436+ goto pscopuop;
437+ case fneg_op:
438+ handler.u = ieee754sp_neg;
439+ goto pscopuop;
440+ case fmov_op:
441+ /* an easy one */
442+ PSPFROMREG(rv.s, rv.s2, MIPSInst_FS(ir));
443+ break;
444+
445+ pscopbop: /* paired binary op handler */
446+ {
447+ struct _ieee754_csr ieee754_csr_save;
448+ ieee754sp fs1, ft1;
449+ ieee754sp fs2, ft2;
450+
451+ PSPFROMREG(fs1, fs2, MIPSInst_FS(ir));
452+ PSPFROMREG(ft1, ft2, MIPSInst_FT(ir));
453+ rv.s = (*handler.b) (fs1, ft1);
454+ ieee754_csr_save = ieee754_csr;
455+ rv.s2 = (*handler.b) (fs2, ft2);
456+ ieee754_csr.cx |= ieee754_csr_save.cx;
457+ ieee754_csr.sx |= ieee754_csr_save.sx;
458+ goto copcsr;
459+ }
460+ pscopuop: /* paired unary op handler */
461+ {
462+ struct _ieee754_csr ieee754_csr_save;
463+ ieee754sp fs1;
464+ ieee754sp fs2;
465+
466+ PSPFROMREG(fs1, fs2, MIPSInst_FS(ir));
467+ rv.s = (*handler.u) (fs1);
468+ ieee754_csr_save = ieee754_csr;
469+ rv.s2 = (*handler.u) (fs2);
470+ ieee754_csr.cx |= ieee754_csr_save.cx;
471+ ieee754_csr.sx |= ieee754_csr_save.sx;
472+ goto copcsr;
473+ }
474+ break;
475+
476+ default:
477+ if (MIPSInst_FUNC(ir) >= fcmp_op) {
478+ /* Loongson fp hardware handles all
479+ cases of fp compare insns, so we
480+ shouldn't have to */
481+ printk ("Loongson paired-single fp compare"
482+ " unimplemented in cp1emu.c\n");
483+ }
484+ return SIGILL;
485+ }
486+ break;
487+ }
488+#endif
489+
490 case w_fmt:{
491 ieee754sp fs;
492
493@@ -1299,6 +1579,11 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
494 DITOREG(rv.l, MIPSInst_FD(ir));
495 break;
496 #endif
497+#ifdef __loongson_fp
498+ case ps_fmt:
499+ PSPTOREG(rv.s, rv.s2, MIPSInst_FD(ir));
500+ break;
501+#endif
502 default:
503 return SIGILL;
504 }
505--
5061.7.5.4
507