aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/math-emu
diff options
context:
space:
mode:
authorWe-unite <3205135446@qq.com>2025-03-08 22:04:20 +0800
committerWe-unite <3205135446@qq.com>2025-03-08 22:04:20 +0800
commita07bb8fd1299070229f0e8f3dcb57ffd5ef9870a (patch)
tree84f21bd0bf7071bc5fc7dd989e77d7ceb5476682 /arch/mips/math-emu
downloadohosKernel-a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a.tar.gz
ohosKernel-a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a.zip
Initial commit: OpenHarmony-v4.0-ReleaseOpenHarmony-v4.0-Release
Diffstat (limited to 'arch/mips/math-emu')
-rw-r--r--arch/mips/math-emu/Makefile19
-rw-r--r--arch/mips/math-emu/cp1emu.c2948
-rw-r--r--arch/mips/math-emu/dp_2008class.c52
-rw-r--r--arch/mips/math-emu/dp_add.c165
-rw-r--r--arch/mips/math-emu/dp_cmp.c47
-rw-r--r--arch/mips/math-emu/dp_div.c143
-rw-r--r--arch/mips/math-emu/dp_fint.c44
-rw-r--r--arch/mips/math-emu/dp_flong.c53
-rw-r--r--arch/mips/math-emu/dp_fmax.c252
-rw-r--r--arch/mips/math-emu/dp_fmin.c252
-rw-r--r--arch/mips/math-emu/dp_fsp.c63
-rw-r--r--arch/mips/math-emu/dp_maddf.c358
-rw-r--r--arch/mips/math-emu/dp_mul.c159
-rw-r--r--arch/mips/math-emu/dp_rint.c78
-rw-r--r--arch/mips/math-emu/dp_simple.c49
-rw-r--r--arch/mips/math-emu/dp_sqrt.c152
-rw-r--r--arch/mips/math-emu/dp_sub.c172
-rw-r--r--arch/mips/math-emu/dp_tint.c96
-rw-r--r--arch/mips/math-emu/dp_tlong.c100
-rw-r--r--arch/mips/math-emu/dsemul.c308
-rw-r--r--arch/mips/math-emu/ieee754.c83
-rw-r--r--arch/mips/math-emu/ieee754.h311
-rw-r--r--arch/mips/math-emu/ieee754d.c99
-rw-r--r--arch/mips/math-emu/ieee754dp.c197
-rw-r--r--arch/mips/math-emu/ieee754dp.h73
-rw-r--r--arch/mips/math-emu/ieee754int.h149
-rw-r--r--arch/mips/math-emu/ieee754sp.c196
-rw-r--r--arch/mips/math-emu/ieee754sp.h77
-rw-r--r--arch/mips/math-emu/me-debugfs.c353
-rw-r--r--arch/mips/math-emu/sp_2008class.c52
-rw-r--r--arch/mips/math-emu/sp_add.c164
-rw-r--r--arch/mips/math-emu/sp_cmp.c47
-rw-r--r--arch/mips/math-emu/sp_div.c142
-rw-r--r--arch/mips/math-emu/sp_fdp.c73
-rw-r--r--arch/mips/math-emu/sp_fint.c53
-rw-r--r--arch/mips/math-emu/sp_flong.c52
-rw-r--r--arch/mips/math-emu/sp_fmax.c252
-rw-r--r--arch/mips/math-emu/sp_fmin.c252
-rw-r--r--arch/mips/math-emu/sp_maddf.c278
-rw-r--r--arch/mips/math-emu/sp_mul.c154
-rw-r--r--arch/mips/math-emu/sp_rint.c79
-rw-r--r--arch/mips/math-emu/sp_simple.c49
-rw-r--r--arch/mips/math-emu/sp_sqrt.c103
-rw-r--r--arch/mips/math-emu/sp_sub.c168
-rw-r--r--arch/mips/math-emu/sp_tint.c100
-rw-r--r--arch/mips/math-emu/sp_tlong.c96
46 files changed, 9162 insertions, 0 deletions
diff --git a/arch/mips/math-emu/Makefile b/arch/mips/math-emu/Makefile
new file mode 100644
index 000000000..81d25ff32
--- /dev/null
+++ b/arch/mips/math-emu/Makefile
@@ -0,0 +1,19 @@
1# SPDX-License-Identifier: GPL-2.0
2#
3# Makefile for the Linux/MIPS kernel FPU emulation.
4#
5
6obj-y += cp1emu.o ieee754dp.o ieee754sp.o ieee754.o \
7 dp_div.o dp_mul.o dp_sub.o dp_add.o dp_fsp.o dp_cmp.o dp_simple.o \
8 dp_tint.o dp_fint.o dp_rint.o dp_maddf.o dp_2008class.o dp_fmin.o \
9 dp_fmax.o \
10 sp_div.o sp_mul.o sp_sub.o sp_add.o sp_fdp.o sp_cmp.o sp_simple.o \
11 sp_tint.o sp_fint.o sp_rint.o sp_maddf.o sp_2008class.o sp_fmin.o \
12 sp_fmax.o \
13 dsemul.o
14
15lib-y += ieee754d.o \
16 dp_tlong.o dp_flong.o dp_sqrt.o \
17 sp_tlong.o sp_flong.o sp_sqrt.o
18
19obj-$(CONFIG_DEBUG_FS) += me-debugfs.o
diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c
new file mode 100644
index 000000000..587cf1d11
--- /dev/null
+++ b/arch/mips/math-emu/cp1emu.c
@@ -0,0 +1,2948 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * cp1emu.c: a MIPS coprocessor 1 (FPU) instruction emulator
4 *
5 * MIPS floating point support
6 * Copyright (C) 1994-2000 Algorithmics Ltd.
7 *
8 * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
9 * Copyright (C) 2000 MIPS Technologies, Inc.
10 *
11 * A complete emulator for MIPS coprocessor 1 instructions. This is
12 * required for #float(switch) or #float(trap), where it catches all
13 * COP1 instructions via the "CoProcessor Unusable" exception.
14 *
15 * More surprisingly it is also required for #float(ieee), to help out
16 * the hardware FPU at the boundaries of the IEEE-754 representation
17 * (denormalised values, infinities, underflow, etc). It is made
18 * quite nasty because emulation of some non-COP1 instructions is
19 * required, e.g. in branch delay slots.
20 *
21 * Note if you know that you won't have an FPU, then you'll get much
22 * better performance by compiling with -msoft-float!
23 */
24#include <linux/sched.h>
25#include <linux/debugfs.h>
26#include <linux/percpu-defs.h>
27#include <linux/perf_event.h>
28
29#include <asm/branch.h>
30#include <asm/inst.h>
31#include <asm/ptrace.h>
32#include <asm/signal.h>
33#include <linux/uaccess.h>
34
35#include <asm/cpu-info.h>
36#include <asm/processor.h>
37#include <asm/fpu_emulator.h>
38#include <asm/fpu.h>
39#include <asm/mips-r2-to-r6-emul.h>
40
41#include "ieee754.h"
42
43/* Function which emulates a floating point instruction. */
44
45static int fpu_emu(struct pt_regs *, struct mips_fpu_struct *,
46 mips_instruction);
47
48static int fpux_emu(struct pt_regs *,
49 struct mips_fpu_struct *, mips_instruction, void __user **);
50
51/* Control registers */
52
53#define FPCREG_RID 0 /* $0 = revision id */
54#define FPCREG_FCCR 25 /* $25 = fccr */
55#define FPCREG_FEXR 26 /* $26 = fexr */
56#define FPCREG_FENR 28 /* $28 = fenr */
57#define FPCREG_CSR 31 /* $31 = csr */
58
59/* convert condition code register number to csr bit */
60const unsigned int fpucondbit[8] = {
61 FPU_CSR_COND,
62 FPU_CSR_COND1,
63 FPU_CSR_COND2,
64 FPU_CSR_COND3,
65 FPU_CSR_COND4,
66 FPU_CSR_COND5,
67 FPU_CSR_COND6,
68 FPU_CSR_COND7
69};
70
71/* (microMIPS) Convert certain microMIPS instructions to MIPS32 format. */
72static const int sd_format[] = {16, 17, 0, 0, 0, 0, 0, 0};
73static const int sdps_format[] = {16, 17, 22, 0, 0, 0, 0, 0};
74static const int dwl_format[] = {17, 20, 21, 0, 0, 0, 0, 0};
75static const int swl_format[] = {16, 20, 21, 0, 0, 0, 0, 0};
76
77/*
78 * This functions translates a 32-bit microMIPS instruction
79 * into a 32-bit MIPS32 instruction. Returns 0 on success
80 * and SIGILL otherwise.
81 */
82static int microMIPS32_to_MIPS32(union mips_instruction *insn_ptr)
83{
84 union mips_instruction insn = *insn_ptr;
85 union mips_instruction mips32_insn = insn;
86 int func, fmt, op;
87
88 switch (insn.mm_i_format.opcode) {
89 case mm_ldc132_op:
90 mips32_insn.mm_i_format.opcode = ldc1_op;
91 mips32_insn.mm_i_format.rt = insn.mm_i_format.rs;
92 mips32_insn.mm_i_format.rs = insn.mm_i_format.rt;
93 break;
94 case mm_lwc132_op:
95 mips32_insn.mm_i_format.opcode = lwc1_op;
96 mips32_insn.mm_i_format.rt = insn.mm_i_format.rs;
97 mips32_insn.mm_i_format.rs = insn.mm_i_format.rt;
98 break;
99 case mm_sdc132_op:
100 mips32_insn.mm_i_format.opcode = sdc1_op;
101 mips32_insn.mm_i_format.rt = insn.mm_i_format.rs;
102 mips32_insn.mm_i_format.rs = insn.mm_i_format.rt;
103 break;
104 case mm_swc132_op:
105 mips32_insn.mm_i_format.opcode = swc1_op;
106 mips32_insn.mm_i_format.rt = insn.mm_i_format.rs;
107 mips32_insn.mm_i_format.rs = insn.mm_i_format.rt;
108 break;
109 case mm_pool32i_op:
110 /* NOTE: offset is << by 1 if in microMIPS mode. */
111 if ((insn.mm_i_format.rt == mm_bc1f_op) ||
112 (insn.mm_i_format.rt == mm_bc1t_op)) {
113 mips32_insn.fb_format.opcode = cop1_op;
114 mips32_insn.fb_format.bc = bc_op;
115 mips32_insn.fb_format.flag =
116 (insn.mm_i_format.rt == mm_bc1t_op) ? 1 : 0;
117 } else
118 return SIGILL;
119 break;
120 case mm_pool32f_op:
121 switch (insn.mm_fp0_format.func) {
122 case mm_32f_01_op:
123 case mm_32f_11_op:
124 case mm_32f_02_op:
125 case mm_32f_12_op:
126 case mm_32f_41_op:
127 case mm_32f_51_op:
128 case mm_32f_42_op:
129 case mm_32f_52_op:
130 op = insn.mm_fp0_format.func;
131 if (op == mm_32f_01_op)
132 func = madd_s_op;
133 else if (op == mm_32f_11_op)
134 func = madd_d_op;
135 else if (op == mm_32f_02_op)
136 func = nmadd_s_op;
137 else if (op == mm_32f_12_op)
138 func = nmadd_d_op;
139 else if (op == mm_32f_41_op)
140 func = msub_s_op;
141 else if (op == mm_32f_51_op)
142 func = msub_d_op;
143 else if (op == mm_32f_42_op)
144 func = nmsub_s_op;
145 else
146 func = nmsub_d_op;
147 mips32_insn.fp6_format.opcode = cop1x_op;
148 mips32_insn.fp6_format.fr = insn.mm_fp6_format.fr;
149 mips32_insn.fp6_format.ft = insn.mm_fp6_format.ft;
150 mips32_insn.fp6_format.fs = insn.mm_fp6_format.fs;
151 mips32_insn.fp6_format.fd = insn.mm_fp6_format.fd;
152 mips32_insn.fp6_format.func = func;
153 break;
154 case mm_32f_10_op:
155 func = -1; /* Invalid */
156 op = insn.mm_fp5_format.op & 0x7;
157 if (op == mm_ldxc1_op)
158 func = ldxc1_op;
159 else if (op == mm_sdxc1_op)
160 func = sdxc1_op;
161 else if (op == mm_lwxc1_op)
162 func = lwxc1_op;
163 else if (op == mm_swxc1_op)
164 func = swxc1_op;
165
166 if (func != -1) {
167 mips32_insn.r_format.opcode = cop1x_op;
168 mips32_insn.r_format.rs =
169 insn.mm_fp5_format.base;
170 mips32_insn.r_format.rt =
171 insn.mm_fp5_format.index;
172 mips32_insn.r_format.rd = 0;
173 mips32_insn.r_format.re = insn.mm_fp5_format.fd;
174 mips32_insn.r_format.func = func;
175 } else
176 return SIGILL;
177 break;
178 case mm_32f_40_op:
179 op = -1; /* Invalid */
180 if (insn.mm_fp2_format.op == mm_fmovt_op)
181 op = 1;
182 else if (insn.mm_fp2_format.op == mm_fmovf_op)
183 op = 0;
184 if (op != -1) {
185 mips32_insn.fp0_format.opcode = cop1_op;
186 mips32_insn.fp0_format.fmt =
187 sdps_format[insn.mm_fp2_format.fmt];
188 mips32_insn.fp0_format.ft =
189 (insn.mm_fp2_format.cc<<2) + op;
190 mips32_insn.fp0_format.fs =
191 insn.mm_fp2_format.fs;
192 mips32_insn.fp0_format.fd =
193 insn.mm_fp2_format.fd;
194 mips32_insn.fp0_format.func = fmovc_op;
195 } else
196 return SIGILL;
197 break;
198 case mm_32f_60_op:
199 func = -1; /* Invalid */
200 if (insn.mm_fp0_format.op == mm_fadd_op)
201 func = fadd_op;
202 else if (insn.mm_fp0_format.op == mm_fsub_op)
203 func = fsub_op;
204 else if (insn.mm_fp0_format.op == mm_fmul_op)
205 func = fmul_op;
206 else if (insn.mm_fp0_format.op == mm_fdiv_op)
207 func = fdiv_op;
208 if (func != -1) {
209 mips32_insn.fp0_format.opcode = cop1_op;
210 mips32_insn.fp0_format.fmt =
211 sdps_format[insn.mm_fp0_format.fmt];
212 mips32_insn.fp0_format.ft =
213 insn.mm_fp0_format.ft;
214 mips32_insn.fp0_format.fs =
215 insn.mm_fp0_format.fs;
216 mips32_insn.fp0_format.fd =
217 insn.mm_fp0_format.fd;
218 mips32_insn.fp0_format.func = func;
219 } else
220 return SIGILL;
221 break;
222 case mm_32f_70_op:
223 func = -1; /* Invalid */
224 if (insn.mm_fp0_format.op == mm_fmovn_op)
225 func = fmovn_op;
226 else if (insn.mm_fp0_format.op == mm_fmovz_op)
227 func = fmovz_op;
228 if (func != -1) {
229 mips32_insn.fp0_format.opcode = cop1_op;
230 mips32_insn.fp0_format.fmt =
231 sdps_format[insn.mm_fp0_format.fmt];
232 mips32_insn.fp0_format.ft =
233 insn.mm_fp0_format.ft;
234 mips32_insn.fp0_format.fs =
235 insn.mm_fp0_format.fs;
236 mips32_insn.fp0_format.fd =
237 insn.mm_fp0_format.fd;
238 mips32_insn.fp0_format.func = func;
239 } else
240 return SIGILL;
241 break;
242 case mm_32f_73_op: /* POOL32FXF */
243 switch (insn.mm_fp1_format.op) {
244 case mm_movf0_op:
245 case mm_movf1_op:
246 case mm_movt0_op:
247 case mm_movt1_op:
248 if ((insn.mm_fp1_format.op & 0x7f) ==
249 mm_movf0_op)
250 op = 0;
251 else
252 op = 1;
253 mips32_insn.r_format.opcode = spec_op;
254 mips32_insn.r_format.rs = insn.mm_fp4_format.fs;
255 mips32_insn.r_format.rt =
256 (insn.mm_fp4_format.cc << 2) + op;
257 mips32_insn.r_format.rd = insn.mm_fp4_format.rt;
258 mips32_insn.r_format.re = 0;
259 mips32_insn.r_format.func = movc_op;
260 break;
261 case mm_fcvtd0_op:
262 case mm_fcvtd1_op:
263 case mm_fcvts0_op:
264 case mm_fcvts1_op:
265 if ((insn.mm_fp1_format.op & 0x7f) ==
266 mm_fcvtd0_op) {
267 func = fcvtd_op;
268 fmt = swl_format[insn.mm_fp3_format.fmt];
269 } else {
270 func = fcvts_op;
271 fmt = dwl_format[insn.mm_fp3_format.fmt];
272 }
273 mips32_insn.fp0_format.opcode = cop1_op;
274 mips32_insn.fp0_format.fmt = fmt;
275 mips32_insn.fp0_format.ft = 0;
276 mips32_insn.fp0_format.fs =
277 insn.mm_fp3_format.fs;
278 mips32_insn.fp0_format.fd =
279 insn.mm_fp3_format.rt;
280 mips32_insn.fp0_format.func = func;
281 break;
282 case mm_fmov0_op:
283 case mm_fmov1_op:
284 case mm_fabs0_op:
285 case mm_fabs1_op:
286 case mm_fneg0_op:
287 case mm_fneg1_op:
288 if ((insn.mm_fp1_format.op & 0x7f) ==
289 mm_fmov0_op)
290 func = fmov_op;
291 else if ((insn.mm_fp1_format.op & 0x7f) ==
292 mm_fabs0_op)
293 func = fabs_op;
294 else
295 func = fneg_op;
296 mips32_insn.fp0_format.opcode = cop1_op;
297 mips32_insn.fp0_format.fmt =
298 sdps_format[insn.mm_fp3_format.fmt];
299 mips32_insn.fp0_format.ft = 0;
300 mips32_insn.fp0_format.fs =
301 insn.mm_fp3_format.fs;
302 mips32_insn.fp0_format.fd =
303 insn.mm_fp3_format.rt;
304 mips32_insn.fp0_format.func = func;
305 break;
306 case mm_ffloorl_op:
307 case mm_ffloorw_op:
308 case mm_fceill_op:
309 case mm_fceilw_op:
310 case mm_ftruncl_op:
311 case mm_ftruncw_op:
312 case mm_froundl_op:
313 case mm_froundw_op:
314 case mm_fcvtl_op:
315 case mm_fcvtw_op:
316 if (insn.mm_fp1_format.op == mm_ffloorl_op)
317 func = ffloorl_op;
318 else if (insn.mm_fp1_format.op == mm_ffloorw_op)
319 func = ffloor_op;
320 else if (insn.mm_fp1_format.op == mm_fceill_op)
321 func = fceill_op;
322 else if (insn.mm_fp1_format.op == mm_fceilw_op)
323 func = fceil_op;
324 else if (insn.mm_fp1_format.op == mm_ftruncl_op)
325 func = ftruncl_op;
326 else if (insn.mm_fp1_format.op == mm_ftruncw_op)
327 func = ftrunc_op;
328 else if (insn.mm_fp1_format.op == mm_froundl_op)
329 func = froundl_op;
330 else if (insn.mm_fp1_format.op == mm_froundw_op)
331 func = fround_op;
332 else if (insn.mm_fp1_format.op == mm_fcvtl_op)
333 func = fcvtl_op;
334 else
335 func = fcvtw_op;
336 mips32_insn.fp0_format.opcode = cop1_op;
337 mips32_insn.fp0_format.fmt =
338 sd_format[insn.mm_fp1_format.fmt];
339 mips32_insn.fp0_format.ft = 0;
340 mips32_insn.fp0_format.fs =
341 insn.mm_fp1_format.fs;
342 mips32_insn.fp0_format.fd =
343 insn.mm_fp1_format.rt;
344 mips32_insn.fp0_format.func = func;
345 break;
346 case mm_frsqrt_op:
347 case mm_fsqrt_op:
348 case mm_frecip_op:
349 if (insn.mm_fp1_format.op == mm_frsqrt_op)
350 func = frsqrt_op;
351 else if (insn.mm_fp1_format.op == mm_fsqrt_op)
352 func = fsqrt_op;
353 else
354 func = frecip_op;
355 mips32_insn.fp0_format.opcode = cop1_op;
356 mips32_insn.fp0_format.fmt =
357 sdps_format[insn.mm_fp1_format.fmt];
358 mips32_insn.fp0_format.ft = 0;
359 mips32_insn.fp0_format.fs =
360 insn.mm_fp1_format.fs;
361 mips32_insn.fp0_format.fd =
362 insn.mm_fp1_format.rt;
363 mips32_insn.fp0_format.func = func;
364 break;
365 case mm_mfc1_op:
366 case mm_mtc1_op:
367 case mm_cfc1_op:
368 case mm_ctc1_op:
369 case mm_mfhc1_op:
370 case mm_mthc1_op:
371 if (insn.mm_fp1_format.op == mm_mfc1_op)
372 op = mfc_op;
373 else if (insn.mm_fp1_format.op == mm_mtc1_op)
374 op = mtc_op;
375 else if (insn.mm_fp1_format.op == mm_cfc1_op)
376 op = cfc_op;
377 else if (insn.mm_fp1_format.op == mm_ctc1_op)
378 op = ctc_op;
379 else if (insn.mm_fp1_format.op == mm_mfhc1_op)
380 op = mfhc_op;
381 else
382 op = mthc_op;
383 mips32_insn.fp1_format.opcode = cop1_op;
384 mips32_insn.fp1_format.op = op;
385 mips32_insn.fp1_format.rt =
386 insn.mm_fp1_format.rt;
387 mips32_insn.fp1_format.fs =
388 insn.mm_fp1_format.fs;
389 mips32_insn.fp1_format.fd = 0;
390 mips32_insn.fp1_format.func = 0;
391 break;
392 default:
393 return SIGILL;
394 }
395 break;
396 case mm_32f_74_op: /* c.cond.fmt */
397 mips32_insn.fp0_format.opcode = cop1_op;
398 mips32_insn.fp0_format.fmt =
399 sdps_format[insn.mm_fp4_format.fmt];
400 mips32_insn.fp0_format.ft = insn.mm_fp4_format.rt;
401 mips32_insn.fp0_format.fs = insn.mm_fp4_format.fs;
402 mips32_insn.fp0_format.fd = insn.mm_fp4_format.cc << 2;
403 mips32_insn.fp0_format.func =
404 insn.mm_fp4_format.cond | MM_MIPS32_COND_FC;
405 break;
406 default:
407 return SIGILL;
408 }
409 break;
410 default:
411 return SIGILL;
412 }
413
414 *insn_ptr = mips32_insn;
415 return 0;
416}
417
418/*
419 * Redundant with logic already in kernel/branch.c,
420 * embedded in compute_return_epc. At some point,
421 * a single subroutine should be used across both
422 * modules.
423 */
424int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
425 unsigned long *contpc)
426{
427 union mips_instruction insn = (union mips_instruction)dec_insn.insn;
428 unsigned int fcr31;
429 unsigned int bit = 0;
430 unsigned int bit0;
431 union fpureg *fpr;
432
433 switch (insn.i_format.opcode) {
434 case spec_op:
435 switch (insn.r_format.func) {
436 case jalr_op:
437 if (insn.r_format.rd != 0) {
438 regs->regs[insn.r_format.rd] =
439 regs->cp0_epc + dec_insn.pc_inc +
440 dec_insn.next_pc_inc;
441 }
442 fallthrough;
443 case jr_op:
444 /* For R6, JR already emulated in jalr_op */
445 if (NO_R6EMU && insn.r_format.func == jr_op)
446 break;
447 *contpc = regs->regs[insn.r_format.rs];
448 return 1;
449 }
450 break;
451 case bcond_op:
452 switch (insn.i_format.rt) {
453 case bltzal_op:
454 case bltzall_op:
455 if (NO_R6EMU && (insn.i_format.rs ||
456 insn.i_format.rt == bltzall_op))
457 break;
458
459 regs->regs[31] = regs->cp0_epc +
460 dec_insn.pc_inc +
461 dec_insn.next_pc_inc;
462 fallthrough;
463 case bltzl_op:
464 if (NO_R6EMU)
465 break;
466 fallthrough;
467 case bltz_op:
468 if ((long)regs->regs[insn.i_format.rs] < 0)
469 *contpc = regs->cp0_epc +
470 dec_insn.pc_inc +
471 (insn.i_format.simmediate << 2);
472 else
473 *contpc = regs->cp0_epc +
474 dec_insn.pc_inc +
475 dec_insn.next_pc_inc;
476 return 1;
477 case bgezal_op:
478 case bgezall_op:
479 if (NO_R6EMU && (insn.i_format.rs ||
480 insn.i_format.rt == bgezall_op))
481 break;
482
483 regs->regs[31] = regs->cp0_epc +
484 dec_insn.pc_inc +
485 dec_insn.next_pc_inc;
486 fallthrough;
487 case bgezl_op:
488 if (NO_R6EMU)
489 break;
490 fallthrough;
491 case bgez_op:
492 if ((long)regs->regs[insn.i_format.rs] >= 0)
493 *contpc = regs->cp0_epc +
494 dec_insn.pc_inc +
495 (insn.i_format.simmediate << 2);
496 else
497 *contpc = regs->cp0_epc +
498 dec_insn.pc_inc +
499 dec_insn.next_pc_inc;
500 return 1;
501 }
502 break;
503 case jalx_op:
504 set_isa16_mode(bit);
505 fallthrough;
506 case jal_op:
507 regs->regs[31] = regs->cp0_epc +
508 dec_insn.pc_inc +
509 dec_insn.next_pc_inc;
510 fallthrough;
511 case j_op:
512 *contpc = regs->cp0_epc + dec_insn.pc_inc;
513 *contpc >>= 28;
514 *contpc <<= 28;
515 *contpc |= (insn.j_format.target << 2);
516 /* Set microMIPS mode bit: XOR for jalx. */
517 *contpc ^= bit;
518 return 1;
519 case beql_op:
520 if (NO_R6EMU)
521 break;
522 fallthrough;
523 case beq_op:
524 if (regs->regs[insn.i_format.rs] ==
525 regs->regs[insn.i_format.rt])
526 *contpc = regs->cp0_epc +
527 dec_insn.pc_inc +
528 (insn.i_format.simmediate << 2);
529 else
530 *contpc = regs->cp0_epc +
531 dec_insn.pc_inc +
532 dec_insn.next_pc_inc;
533 return 1;
534 case bnel_op:
535 if (NO_R6EMU)
536 break;
537 fallthrough;
538 case bne_op:
539 if (regs->regs[insn.i_format.rs] !=
540 regs->regs[insn.i_format.rt])
541 *contpc = regs->cp0_epc +
542 dec_insn.pc_inc +
543 (insn.i_format.simmediate << 2);
544 else
545 *contpc = regs->cp0_epc +
546 dec_insn.pc_inc +
547 dec_insn.next_pc_inc;
548 return 1;
549 case blezl_op:
550 if (!insn.i_format.rt && NO_R6EMU)
551 break;
552 fallthrough;
553 case blez_op:
554
555 /*
556 * Compact branches for R6 for the
557 * blez and blezl opcodes.
558 * BLEZ | rs = 0 | rt != 0 == BLEZALC
559 * BLEZ | rs = rt != 0 == BGEZALC
560 * BLEZ | rs != 0 | rt != 0 == BGEUC
561 * BLEZL | rs = 0 | rt != 0 == BLEZC
562 * BLEZL | rs = rt != 0 == BGEZC
563 * BLEZL | rs != 0 | rt != 0 == BGEC
564 *
565 * For real BLEZ{,L}, rt is always 0.
566 */
567 if (cpu_has_mips_r6 && insn.i_format.rt) {
568 if ((insn.i_format.opcode == blez_op) &&
569 ((!insn.i_format.rs && insn.i_format.rt) ||
570 (insn.i_format.rs == insn.i_format.rt)))
571 regs->regs[31] = regs->cp0_epc +
572 dec_insn.pc_inc;
573 *contpc = regs->cp0_epc + dec_insn.pc_inc +
574 dec_insn.next_pc_inc;
575
576 return 1;
577 }
578 if ((long)regs->regs[insn.i_format.rs] <= 0)
579 *contpc = regs->cp0_epc +
580 dec_insn.pc_inc +
581 (insn.i_format.simmediate << 2);
582 else
583 *contpc = regs->cp0_epc +
584 dec_insn.pc_inc +
585 dec_insn.next_pc_inc;
586 return 1;
587 case bgtzl_op:
588 if (!insn.i_format.rt && NO_R6EMU)
589 break;
590 fallthrough;
591 case bgtz_op:
592 /*
593 * Compact branches for R6 for the
594 * bgtz and bgtzl opcodes.
595 * BGTZ | rs = 0 | rt != 0 == BGTZALC
596 * BGTZ | rs = rt != 0 == BLTZALC
597 * BGTZ | rs != 0 | rt != 0 == BLTUC
598 * BGTZL | rs = 0 | rt != 0 == BGTZC
599 * BGTZL | rs = rt != 0 == BLTZC
600 * BGTZL | rs != 0 | rt != 0 == BLTC
601 *
602 * *ZALC varint for BGTZ &&& rt != 0
603 * For real GTZ{,L}, rt is always 0.
604 */
605 if (cpu_has_mips_r6 && insn.i_format.rt) {
606 if ((insn.i_format.opcode == blez_op) &&
607 ((!insn.i_format.rs && insn.i_format.rt) ||
608 (insn.i_format.rs == insn.i_format.rt)))
609 regs->regs[31] = regs->cp0_epc +
610 dec_insn.pc_inc;
611 *contpc = regs->cp0_epc + dec_insn.pc_inc +
612 dec_insn.next_pc_inc;
613
614 return 1;
615 }
616
617 if ((long)regs->regs[insn.i_format.rs] > 0)
618 *contpc = regs->cp0_epc +
619 dec_insn.pc_inc +
620 (insn.i_format.simmediate << 2);
621 else
622 *contpc = regs->cp0_epc +
623 dec_insn.pc_inc +
624 dec_insn.next_pc_inc;
625 return 1;
626 case pop10_op:
627 case pop30_op:
628 if (!cpu_has_mips_r6)
629 break;
630 if (insn.i_format.rt && !insn.i_format.rs)
631 regs->regs[31] = regs->cp0_epc + 4;
632 *contpc = regs->cp0_epc + dec_insn.pc_inc +
633 dec_insn.next_pc_inc;
634
635 return 1;
636#ifdef CONFIG_CPU_CAVIUM_OCTEON
637 case lwc2_op: /* This is bbit0 on Octeon */
638 if ((regs->regs[insn.i_format.rs] & (1ull<<insn.i_format.rt)) == 0)
639 *contpc = regs->cp0_epc + 4 + (insn.i_format.simmediate << 2);
640 else
641 *contpc = regs->cp0_epc + 8;
642 return 1;
643 case ldc2_op: /* This is bbit032 on Octeon */
644 if ((regs->regs[insn.i_format.rs] & (1ull<<(insn.i_format.rt + 32))) == 0)
645 *contpc = regs->cp0_epc + 4 + (insn.i_format.simmediate << 2);
646 else
647 *contpc = regs->cp0_epc + 8;
648 return 1;
649 case swc2_op: /* This is bbit1 on Octeon */
650 if (regs->regs[insn.i_format.rs] & (1ull<<insn.i_format.rt))
651 *contpc = regs->cp0_epc + 4 + (insn.i_format.simmediate << 2);
652 else
653 *contpc = regs->cp0_epc + 8;
654 return 1;
655 case sdc2_op: /* This is bbit132 on Octeon */
656 if (regs->regs[insn.i_format.rs] & (1ull<<(insn.i_format.rt + 32)))
657 *contpc = regs->cp0_epc + 4 + (insn.i_format.simmediate << 2);
658 else
659 *contpc = regs->cp0_epc + 8;
660 return 1;
661#else
662 case bc6_op:
663 /*
664 * Only valid for MIPS R6 but we can still end up
665 * here from a broken userland so just tell emulator
666 * this is not a branch and let it break later on.
667 */
668 if (!cpu_has_mips_r6)
669 break;
670 *contpc = regs->cp0_epc + dec_insn.pc_inc +
671 dec_insn.next_pc_inc;
672
673 return 1;
674 case balc6_op:
675 if (!cpu_has_mips_r6)
676 break;
677 regs->regs[31] = regs->cp0_epc + 4;
678 *contpc = regs->cp0_epc + dec_insn.pc_inc +
679 dec_insn.next_pc_inc;
680
681 return 1;
682 case pop66_op:
683 if (!cpu_has_mips_r6)
684 break;
685 *contpc = regs->cp0_epc + dec_insn.pc_inc +
686 dec_insn.next_pc_inc;
687
688 return 1;
689 case pop76_op:
690 if (!cpu_has_mips_r6)
691 break;
692 if (!insn.i_format.rs)
693 regs->regs[31] = regs->cp0_epc + 4;
694 *contpc = regs->cp0_epc + dec_insn.pc_inc +
695 dec_insn.next_pc_inc;
696
697 return 1;
698#endif
699 case cop0_op:
700 case cop1_op:
701 /* Need to check for R6 bc1nez and bc1eqz branches */
702 if (cpu_has_mips_r6 &&
703 ((insn.i_format.rs == bc1eqz_op) ||
704 (insn.i_format.rs == bc1nez_op))) {
705 bit = 0;
706 fpr = &current->thread.fpu.fpr[insn.i_format.rt];
707 bit0 = get_fpr32(fpr, 0) & 0x1;
708 switch (insn.i_format.rs) {
709 case bc1eqz_op:
710 bit = bit0 == 0;
711 break;
712 case bc1nez_op:
713 bit = bit0 != 0;
714 break;
715 }
716 if (bit)
717 *contpc = regs->cp0_epc +
718 dec_insn.pc_inc +
719 (insn.i_format.simmediate << 2);
720 else
721 *contpc = regs->cp0_epc +
722 dec_insn.pc_inc +
723 dec_insn.next_pc_inc;
724
725 return 1;
726 }
727 /* R2/R6 compatible cop1 instruction */
728 fallthrough;
729 case cop2_op:
730 case cop1x_op:
731 if (insn.i_format.rs == bc_op) {
732 preempt_disable();
733 if (is_fpu_owner())
734 fcr31 = read_32bit_cp1_register(CP1_STATUS);
735 else
736 fcr31 = current->thread.fpu.fcr31;
737 preempt_enable();
738
739 bit = (insn.i_format.rt >> 2);
740 bit += (bit != 0);
741 bit += 23;
742 switch (insn.i_format.rt & 3) {
743 case 0: /* bc1f */
744 case 2: /* bc1fl */
745 if (~fcr31 & (1 << bit))
746 *contpc = regs->cp0_epc +
747 dec_insn.pc_inc +
748 (insn.i_format.simmediate << 2);
749 else
750 *contpc = regs->cp0_epc +
751 dec_insn.pc_inc +
752 dec_insn.next_pc_inc;
753 return 1;
754 case 1: /* bc1t */
755 case 3: /* bc1tl */
756 if (fcr31 & (1 << bit))
757 *contpc = regs->cp0_epc +
758 dec_insn.pc_inc +
759 (insn.i_format.simmediate << 2);
760 else
761 *contpc = regs->cp0_epc +
762 dec_insn.pc_inc +
763 dec_insn.next_pc_inc;
764 return 1;
765 }
766 }
767 break;
768 }
769 return 0;
770}
771
772/*
773 * In the Linux kernel, we support selection of FPR format on the
774 * basis of the Status.FR bit. If an FPU is not present, the FR bit
775 * is hardwired to zero, which would imply a 32-bit FPU even for
776 * 64-bit CPUs so we rather look at TIF_32BIT_FPREGS.
777 * FPU emu is slow and bulky and optimizing this function offers fairly
778 * sizeable benefits so we try to be clever and make this function return
779 * a constant whenever possible, that is on 64-bit kernels without O32
780 * compatibility enabled and on 32-bit without 64-bit FPU support.
781 */
782static inline int cop1_64bit(struct pt_regs *xcp)
783{
784 if (IS_ENABLED(CONFIG_64BIT) && !IS_ENABLED(CONFIG_MIPS32_O32))
785 return 1;
786 else if (IS_ENABLED(CONFIG_32BIT) &&
787 !IS_ENABLED(CONFIG_MIPS_O32_FP64_SUPPORT))
788 return 0;
789
790 return !test_thread_flag(TIF_32BIT_FPREGS);
791}
792
793static inline bool hybrid_fprs(void)
794{
795 return test_thread_flag(TIF_HYBRID_FPREGS);
796}
797
798#define SIFROMREG(si, x) \
799do { \
800 if (cop1_64bit(xcp) && !hybrid_fprs()) \
801 (si) = (int)get_fpr32(&ctx->fpr[x], 0); \
802 else \
803 (si) = (int)get_fpr32(&ctx->fpr[(x) & ~1], (x) & 1); \
804} while (0)
805
806#define SITOREG(si, x) \
807do { \
808 if (cop1_64bit(xcp) && !hybrid_fprs()) { \
809 unsigned int i; \
810 set_fpr32(&ctx->fpr[x], 0, si); \
811 for (i = 1; i < ARRAY_SIZE(ctx->fpr[x].val32); i++) \
812 set_fpr32(&ctx->fpr[x], i, 0); \
813 } else { \
814 set_fpr32(&ctx->fpr[(x) & ~1], (x) & 1, si); \
815 } \
816} while (0)
817
818#define SIFROMHREG(si, x) ((si) = (int)get_fpr32(&ctx->fpr[x], 1))
819
820#define SITOHREG(si, x) \
821do { \
822 unsigned int i; \
823 set_fpr32(&ctx->fpr[x], 1, si); \
824 for (i = 2; i < ARRAY_SIZE(ctx->fpr[x].val32); i++) \
825 set_fpr32(&ctx->fpr[x], i, 0); \
826} while (0)
827
828#define DIFROMREG(di, x) \
829 ((di) = get_fpr64(&ctx->fpr[(x) & ~(cop1_64bit(xcp) ^ 1)], 0))
830
831#define DITOREG(di, x) \
832do { \
833 unsigned int fpr, i; \
834 fpr = (x) & ~(cop1_64bit(xcp) ^ 1); \
835 set_fpr64(&ctx->fpr[fpr], 0, di); \
836 for (i = 1; i < ARRAY_SIZE(ctx->fpr[x].val64); i++) \
837 set_fpr64(&ctx->fpr[fpr], i, 0); \
838} while (0)
839
840#define SPFROMREG(sp, x) SIFROMREG((sp).bits, x)
841#define SPTOREG(sp, x) SITOREG((sp).bits, x)
842#define DPFROMREG(dp, x) DIFROMREG((dp).bits, x)
843#define DPTOREG(dp, x) DITOREG((dp).bits, x)
844
845/*
846 * Emulate a CFC1 instruction.
847 */
848static inline void cop1_cfc(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
849 mips_instruction ir)
850{
851 u32 fcr31 = ctx->fcr31;
852 u32 value = 0;
853
854 switch (MIPSInst_RD(ir)) {
855 case FPCREG_CSR:
856 value = fcr31;
857 pr_debug("%p gpr[%d]<-csr=%08x\n",
858 (void *)xcp->cp0_epc, MIPSInst_RT(ir), value);
859 break;
860
861 case FPCREG_FENR:
862 if (!cpu_has_mips_r)
863 break;
864 value = (fcr31 >> (FPU_CSR_FS_S - MIPS_FENR_FS_S)) &
865 MIPS_FENR_FS;
866 value |= fcr31 & (FPU_CSR_ALL_E | FPU_CSR_RM);
867 pr_debug("%p gpr[%d]<-enr=%08x\n",
868 (void *)xcp->cp0_epc, MIPSInst_RT(ir), value);
869 break;
870
871 case FPCREG_FEXR:
872 if (!cpu_has_mips_r)
873 break;
874 value = fcr31 & (FPU_CSR_ALL_X | FPU_CSR_ALL_S);
875 pr_debug("%p gpr[%d]<-exr=%08x\n",
876 (void *)xcp->cp0_epc, MIPSInst_RT(ir), value);
877 break;
878
879 case FPCREG_FCCR:
880 if (!cpu_has_mips_r)
881 break;
882 value = (fcr31 >> (FPU_CSR_COND_S - MIPS_FCCR_COND0_S)) &
883 MIPS_FCCR_COND0;
884 value |= (fcr31 >> (FPU_CSR_COND1_S - MIPS_FCCR_COND1_S)) &
885 (MIPS_FCCR_CONDX & ~MIPS_FCCR_COND0);
886 pr_debug("%p gpr[%d]<-ccr=%08x\n",
887 (void *)xcp->cp0_epc, MIPSInst_RT(ir), value);
888 break;
889
890 case FPCREG_RID:
891 value = boot_cpu_data.fpu_id;
892 break;
893
894 default:
895 break;
896 }
897
898 if (MIPSInst_RT(ir))
899 xcp->regs[MIPSInst_RT(ir)] = value;
900}
901
902/*
903 * Emulate a CTC1 instruction.
904 */
905static inline void cop1_ctc(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
906 mips_instruction ir)
907{
908 u32 fcr31 = ctx->fcr31;
909 u32 value;
910 u32 mask;
911
912 if (MIPSInst_RT(ir) == 0)
913 value = 0;
914 else
915 value = xcp->regs[MIPSInst_RT(ir)];
916
917 switch (MIPSInst_RD(ir)) {
918 case FPCREG_CSR:
919 pr_debug("%p gpr[%d]->csr=%08x\n",
920 (void *)xcp->cp0_epc, MIPSInst_RT(ir), value);
921
922 /* Preserve read-only bits. */
923 mask = boot_cpu_data.fpu_msk31;
924 fcr31 = (value & ~mask) | (fcr31 & mask);
925 break;
926
927 case FPCREG_FENR:
928 if (!cpu_has_mips_r)
929 break;
930 pr_debug("%p gpr[%d]->enr=%08x\n",
931 (void *)xcp->cp0_epc, MIPSInst_RT(ir), value);
932 fcr31 &= ~(FPU_CSR_FS | FPU_CSR_ALL_E | FPU_CSR_RM);
933 fcr31 |= (value << (FPU_CSR_FS_S - MIPS_FENR_FS_S)) &
934 FPU_CSR_FS;
935 fcr31 |= value & (FPU_CSR_ALL_E | FPU_CSR_RM);
936 break;
937
938 case FPCREG_FEXR:
939 if (!cpu_has_mips_r)
940 break;
941 pr_debug("%p gpr[%d]->exr=%08x\n",
942 (void *)xcp->cp0_epc, MIPSInst_RT(ir), value);
943 fcr31 &= ~(FPU_CSR_ALL_X | FPU_CSR_ALL_S);
944 fcr31 |= value & (FPU_CSR_ALL_X | FPU_CSR_ALL_S);
945 break;
946
947 case FPCREG_FCCR:
948 if (!cpu_has_mips_r)
949 break;
950 pr_debug("%p gpr[%d]->ccr=%08x\n",
951 (void *)xcp->cp0_epc, MIPSInst_RT(ir), value);
952 fcr31 &= ~(FPU_CSR_CONDX | FPU_CSR_COND);
953 fcr31 |= (value << (FPU_CSR_COND_S - MIPS_FCCR_COND0_S)) &
954 FPU_CSR_COND;
955 fcr31 |= (value << (FPU_CSR_COND1_S - MIPS_FCCR_COND1_S)) &
956 FPU_CSR_CONDX;
957 break;
958
959 default:
960 break;
961 }
962
963 ctx->fcr31 = fcr31;
964}
965
966/*
967 * Emulate the single floating point instruction pointed at by EPC.
968 * Two instructions if the instruction is in a branch delay slot.
969 */
970
971static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
972 struct mm_decoded_insn dec_insn, void __user **fault_addr)
973{
974 unsigned long contpc = xcp->cp0_epc + dec_insn.pc_inc;
975 unsigned int cond, cbit, bit0;
976 mips_instruction ir;
977 int likely, pc_inc;
978 union fpureg *fpr;
979 u32 __user *wva;
980 u64 __user *dva;
981 u32 wval;
982 u64 dval;
983 int sig;
984
985 /*
986 * These are giving gcc a gentle hint about what to expect in
987 * dec_inst in order to do better optimization.
988 */
989 if (!cpu_has_mmips && dec_insn.micro_mips_mode)
990 unreachable();
991
992 /* XXX NEC Vr54xx bug workaround */
993 if (delay_slot(xcp)) {
994 if (dec_insn.micro_mips_mode) {
995 if (!mm_isBranchInstr(xcp, dec_insn, &contpc))
996 clear_delay_slot(xcp);
997 } else {
998 if (!isBranchInstr(xcp, dec_insn, &contpc))
999 clear_delay_slot(xcp);
1000 }
1001 }
1002
1003 if (delay_slot(xcp)) {
1004 /*
1005 * The instruction to be emulated is in a branch delay slot
1006 * which means that we have to emulate the branch instruction
1007 * BEFORE we do the cop1 instruction.
1008 *
1009 * This branch could be a COP1 branch, but in that case we
1010 * would have had a trap for that instruction, and would not
1011 * come through this route.
1012 *
1013 * Linux MIPS branch emulator operates on context, updating the
1014 * cp0_epc.
1015 */
1016 ir = dec_insn.next_insn; /* process delay slot instr */
1017 pc_inc = dec_insn.next_pc_inc;
1018 } else {
1019 ir = dec_insn.insn; /* process current instr */
1020 pc_inc = dec_insn.pc_inc;
1021 }
1022
1023 /*
1024 * Since microMIPS FPU instructios are a subset of MIPS32 FPU
1025 * instructions, we want to convert microMIPS FPU instructions
1026 * into MIPS32 instructions so that we could reuse all of the
1027 * FPU emulation code.
1028 *
1029 * NOTE: We cannot do this for branch instructions since they
1030 * are not a subset. Example: Cannot emulate a 16-bit
1031 * aligned target address with a MIPS32 instruction.
1032 */
1033 if (dec_insn.micro_mips_mode) {
1034 /*
1035 * If next instruction is a 16-bit instruction, then it
1036 * it cannot be a FPU instruction. This could happen
1037 * since we can be called for non-FPU instructions.
1038 */
1039 if ((pc_inc == 2) ||
1040 (microMIPS32_to_MIPS32((union mips_instruction *)&ir)
1041 == SIGILL))
1042 return SIGILL;
1043 }
1044
1045emul:
1046 perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, xcp, 0);
1047 MIPS_FPU_EMU_INC_STATS(emulated);
1048 switch (MIPSInst_OPCODE(ir)) {
1049 case ldc1_op:
1050 dva = (u64 __user *) (xcp->regs[MIPSInst_RS(ir)] +
1051 MIPSInst_SIMM(ir));
1052 MIPS_FPU_EMU_INC_STATS(loads);
1053
1054 if (!access_ok(dva, sizeof(u64))) {
1055 MIPS_FPU_EMU_INC_STATS(errors);
1056 *fault_addr = dva;
1057 return SIGBUS;
1058 }
1059 if (__get_user(dval, dva)) {
1060 MIPS_FPU_EMU_INC_STATS(errors);
1061 *fault_addr = dva;
1062 return SIGSEGV;
1063 }
1064 DITOREG(dval, MIPSInst_RT(ir));
1065 break;
1066
1067 case sdc1_op:
1068 dva = (u64 __user *) (xcp->regs[MIPSInst_RS(ir)] +
1069 MIPSInst_SIMM(ir));
1070 MIPS_FPU_EMU_INC_STATS(stores);
1071 DIFROMREG(dval, MIPSInst_RT(ir));
1072 if (!access_ok(dva, sizeof(u64))) {
1073 MIPS_FPU_EMU_INC_STATS(errors);
1074 *fault_addr = dva;
1075 return SIGBUS;
1076 }
1077 if (__put_user(dval, dva)) {
1078 MIPS_FPU_EMU_INC_STATS(errors);
1079 *fault_addr = dva;
1080 return SIGSEGV;
1081 }
1082 break;
1083
1084 case lwc1_op:
1085 wva = (u32 __user *) (xcp->regs[MIPSInst_RS(ir)] +
1086 MIPSInst_SIMM(ir));
1087 MIPS_FPU_EMU_INC_STATS(loads);
1088 if (!access_ok(wva, sizeof(u32))) {
1089 MIPS_FPU_EMU_INC_STATS(errors);
1090 *fault_addr = wva;
1091 return SIGBUS;
1092 }
1093 if (__get_user(wval, wva)) {
1094 MIPS_FPU_EMU_INC_STATS(errors);
1095 *fault_addr = wva;
1096 return SIGSEGV;
1097 }
1098 SITOREG(wval, MIPSInst_RT(ir));
1099 break;
1100
1101 case swc1_op:
1102 wva = (u32 __user *) (xcp->regs[MIPSInst_RS(ir)] +
1103 MIPSInst_SIMM(ir));
1104 MIPS_FPU_EMU_INC_STATS(stores);
1105 SIFROMREG(wval, MIPSInst_RT(ir));
1106 if (!access_ok(wva, sizeof(u32))) {
1107 MIPS_FPU_EMU_INC_STATS(errors);
1108 *fault_addr = wva;
1109 return SIGBUS;
1110 }
1111 if (__put_user(wval, wva)) {
1112 MIPS_FPU_EMU_INC_STATS(errors);
1113 *fault_addr = wva;
1114 return SIGSEGV;
1115 }
1116 break;
1117
1118 case cop1_op:
1119 switch (MIPSInst_RS(ir)) {
1120 case dmfc_op:
1121 if (!cpu_has_mips_3_4_5 && !cpu_has_mips64)
1122 return SIGILL;
1123
1124 /* copregister fs -> gpr[rt] */
1125 if (MIPSInst_RT(ir) != 0) {
1126 DIFROMREG(xcp->regs[MIPSInst_RT(ir)],
1127 MIPSInst_RD(ir));
1128 }
1129 break;
1130
1131 case dmtc_op:
1132 if (!cpu_has_mips_3_4_5 && !cpu_has_mips64)
1133 return SIGILL;
1134
1135 /* copregister fs <- rt */
1136 DITOREG(xcp->regs[MIPSInst_RT(ir)], MIPSInst_RD(ir));
1137 break;
1138
1139 case mfhc_op:
1140 if (!cpu_has_mips_r2_r6)
1141 return SIGILL;
1142
1143 /* copregister rd -> gpr[rt] */
1144 if (MIPSInst_RT(ir) != 0) {
1145 SIFROMHREG(xcp->regs[MIPSInst_RT(ir)],
1146 MIPSInst_RD(ir));
1147 }
1148 break;
1149
1150 case mthc_op:
1151 if (!cpu_has_mips_r2_r6)
1152 return SIGILL;
1153
1154 /* copregister rd <- gpr[rt] */
1155 SITOHREG(xcp->regs[MIPSInst_RT(ir)], MIPSInst_RD(ir));
1156 break;
1157
1158 case mfc_op:
1159 /* copregister rd -> gpr[rt] */
1160 if (MIPSInst_RT(ir) != 0) {
1161 SIFROMREG(xcp->regs[MIPSInst_RT(ir)],
1162 MIPSInst_RD(ir));
1163 }
1164 break;
1165
1166 case mtc_op:
1167 /* copregister rd <- rt */
1168 SITOREG(xcp->regs[MIPSInst_RT(ir)], MIPSInst_RD(ir));
1169 break;
1170
1171 case cfc_op:
1172 /* cop control register rd -> gpr[rt] */
1173 cop1_cfc(xcp, ctx, ir);
1174 break;
1175
1176 case ctc_op:
1177 /* copregister rd <- rt */
1178 cop1_ctc(xcp, ctx, ir);
1179 if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) {
1180 return SIGFPE;
1181 }
1182 break;
1183
1184 case bc1eqz_op:
1185 case bc1nez_op:
1186 if (!cpu_has_mips_r6 || delay_slot(xcp))
1187 return SIGILL;
1188
1189 likely = 0;
1190 cond = 0;
1191 fpr = &current->thread.fpu.fpr[MIPSInst_RT(ir)];
1192 bit0 = get_fpr32(fpr, 0) & 0x1;
1193 switch (MIPSInst_RS(ir)) {
1194 case bc1eqz_op:
1195 MIPS_FPU_EMU_INC_STATS(bc1eqz);
1196 cond = bit0 == 0;
1197 break;
1198 case bc1nez_op:
1199 MIPS_FPU_EMU_INC_STATS(bc1nez);
1200 cond = bit0 != 0;
1201 break;
1202 }
1203 goto branch_common;
1204
1205 case bc_op:
1206 if (delay_slot(xcp))
1207 return SIGILL;
1208
1209 if (cpu_has_mips_4_5_r)
1210 cbit = fpucondbit[MIPSInst_RT(ir) >> 2];
1211 else
1212 cbit = FPU_CSR_COND;
1213 cond = ctx->fcr31 & cbit;
1214
1215 likely = 0;
1216 switch (MIPSInst_RT(ir) & 3) {
1217 case bcfl_op:
1218 if (cpu_has_mips_2_3_4_5_r)
1219 likely = 1;
1220 fallthrough;
1221 case bcf_op:
1222 cond = !cond;
1223 break;
1224 case bctl_op:
1225 if (cpu_has_mips_2_3_4_5_r)
1226 likely = 1;
1227 fallthrough;
1228 case bct_op:
1229 break;
1230 }
1231branch_common:
1232 MIPS_FPU_EMU_INC_STATS(branches);
1233 set_delay_slot(xcp);
1234 if (cond) {
1235 /*
1236 * Branch taken: emulate dslot instruction
1237 */
1238 unsigned long bcpc;
1239
1240 /*
1241 * Remember EPC at the branch to point back
1242 * at so that any delay-slot instruction
1243 * signal is not silently ignored.
1244 */
1245 bcpc = xcp->cp0_epc;
1246 xcp->cp0_epc += dec_insn.pc_inc;
1247
1248 contpc = MIPSInst_SIMM(ir);
1249 ir = dec_insn.next_insn;
1250 if (dec_insn.micro_mips_mode) {
1251 contpc = (xcp->cp0_epc + (contpc << 1));
1252
1253 /* If 16-bit instruction, not FPU. */
1254 if ((dec_insn.next_pc_inc == 2) ||
1255 (microMIPS32_to_MIPS32((union mips_instruction *)&ir) == SIGILL)) {
1256
1257 /*
1258 * Since this instruction will
1259 * be put on the stack with
1260 * 32-bit words, get around
1261 * this problem by putting a
1262 * NOP16 as the second one.
1263 */
1264 if (dec_insn.next_pc_inc == 2)
1265 ir = (ir & (~0xffff)) | MM_NOP16;
1266
1267 /*
1268 * Single step the non-CP1
1269 * instruction in the dslot.
1270 */
1271 sig = mips_dsemul(xcp, ir,
1272 bcpc, contpc);
1273 if (sig < 0)
1274 break;
1275 if (sig)
1276 xcp->cp0_epc = bcpc;
1277 /*
1278 * SIGILL forces out of
1279 * the emulation loop.
1280 */
1281 return sig ? sig : SIGILL;
1282 }
1283 } else
1284 contpc = (xcp->cp0_epc + (contpc << 2));
1285
1286 switch (MIPSInst_OPCODE(ir)) {
1287 case lwc1_op:
1288 case swc1_op:
1289 goto emul;
1290
1291 case ldc1_op:
1292 case sdc1_op:
1293 if (cpu_has_mips_2_3_4_5_r)
1294 goto emul;
1295
1296 goto bc_sigill;
1297
1298 case cop1_op:
1299 goto emul;
1300
1301 case cop1x_op:
1302 if (cpu_has_mips_4_5_64_r2_r6)
1303 /* its one of ours */
1304 goto emul;
1305
1306 goto bc_sigill;
1307
1308 case spec_op:
1309 switch (MIPSInst_FUNC(ir)) {
1310 case movc_op:
1311 if (cpu_has_mips_4_5_r)
1312 goto emul;
1313
1314 goto bc_sigill;
1315 }
1316 break;
1317
1318 bc_sigill:
1319 xcp->cp0_epc = bcpc;
1320 return SIGILL;
1321 }
1322
1323 /*
1324 * Single step the non-cp1
1325 * instruction in the dslot
1326 */
1327 sig = mips_dsemul(xcp, ir, bcpc, contpc);
1328 if (sig < 0)
1329 break;
1330 if (sig)
1331 xcp->cp0_epc = bcpc;
1332 /* SIGILL forces out of the emulation loop. */
1333 return sig ? sig : SIGILL;
1334 } else if (likely) { /* branch not taken */
1335 /*
1336 * branch likely nullifies
1337 * dslot if not taken
1338 */
1339 xcp->cp0_epc += dec_insn.pc_inc;
1340 contpc += dec_insn.pc_inc;
1341 /*
1342 * else continue & execute
1343 * dslot as normal insn
1344 */
1345 }
1346 break;
1347
1348 default:
1349 if (!(MIPSInst_RS(ir) & 0x10))
1350 return SIGILL;
1351
1352 /* a real fpu computation instruction */
1353 sig = fpu_emu(xcp, ctx, ir);
1354 if (sig)
1355 return sig;
1356 }
1357 break;
1358
1359 case cop1x_op:
1360 if (!cpu_has_mips_4_5_64_r2_r6)
1361 return SIGILL;
1362
1363 sig = fpux_emu(xcp, ctx, ir, fault_addr);
1364 if (sig)
1365 return sig;
1366 break;
1367
1368 case spec_op:
1369 if (!cpu_has_mips_4_5_r)
1370 return SIGILL;
1371
1372 if (MIPSInst_FUNC(ir) != movc_op)
1373 return SIGILL;
1374 cond = fpucondbit[MIPSInst_RT(ir) >> 2];
1375 if (((ctx->fcr31 & cond) != 0) == ((MIPSInst_RT(ir) & 1) != 0))
1376 xcp->regs[MIPSInst_RD(ir)] =
1377 xcp->regs[MIPSInst_RS(ir)];
1378 break;
1379 default:
1380 return SIGILL;
1381 }
1382
1383 /* we did it !! */
1384 xcp->cp0_epc = contpc;
1385 clear_delay_slot(xcp);
1386
1387 return 0;
1388}
1389
1390/*
1391 * Conversion table from MIPS compare ops 48-63
1392 * cond = ieee754dp_cmp(x,y,IEEE754_UN,sig);
1393 */
1394static const unsigned char cmptab[8] = {
1395 0, /* cmp_0 (sig) cmp_sf */
1396 IEEE754_CUN, /* cmp_un (sig) cmp_ngle */
1397 IEEE754_CEQ, /* cmp_eq (sig) cmp_seq */
1398 IEEE754_CEQ | IEEE754_CUN, /* cmp_ueq (sig) cmp_ngl */
1399 IEEE754_CLT, /* cmp_olt (sig) cmp_lt */
1400 IEEE754_CLT | IEEE754_CUN, /* cmp_ult (sig) cmp_nge */
1401 IEEE754_CLT | IEEE754_CEQ, /* cmp_ole (sig) cmp_le */
1402 IEEE754_CLT | IEEE754_CEQ | IEEE754_CUN, /* cmp_ule (sig) cmp_ngt */
1403};
1404
1405static const unsigned char negative_cmptab[8] = {
1406 0, /* Reserved */
1407 IEEE754_CLT | IEEE754_CGT | IEEE754_CEQ,
1408 IEEE754_CLT | IEEE754_CGT | IEEE754_CUN,
1409 IEEE754_CLT | IEEE754_CGT,
1410 /* Reserved */
1411};
1412
1413
1414/*
1415 * Additional MIPS4 instructions
1416 */
1417
1418#define DEF3OP(name, p, f1, f2, f3) \
1419static union ieee754##p fpemu_##p##_##name(union ieee754##p r, \
1420 union ieee754##p s, union ieee754##p t) \
1421{ \
1422 struct _ieee754_csr ieee754_csr_save; \
1423 s = f1(s, t); \
1424 ieee754_csr_save = ieee754_csr; \
1425 s = f2(s, r); \
1426 ieee754_csr_save.cx |= ieee754_csr.cx; \
1427 ieee754_csr_save.sx |= ieee754_csr.sx; \
1428 s = f3(s); \
1429 ieee754_csr.cx |= ieee754_csr_save.cx; \
1430 ieee754_csr.sx |= ieee754_csr_save.sx; \
1431 return s; \
1432}
1433
1434static union ieee754dp fpemu_dp_recip(union ieee754dp d)
1435{
1436 return ieee754dp_div(ieee754dp_one(0), d);
1437}
1438
1439static union ieee754dp fpemu_dp_rsqrt(union ieee754dp d)
1440{
1441 return ieee754dp_div(ieee754dp_one(0), ieee754dp_sqrt(d));
1442}
1443
1444static union ieee754sp fpemu_sp_recip(union ieee754sp s)
1445{
1446 return ieee754sp_div(ieee754sp_one(0), s);
1447}
1448
1449static union ieee754sp fpemu_sp_rsqrt(union ieee754sp s)
1450{
1451 return ieee754sp_div(ieee754sp_one(0), ieee754sp_sqrt(s));
1452}
1453
1454DEF3OP(madd, sp, ieee754sp_mul, ieee754sp_add, );
1455DEF3OP(msub, sp, ieee754sp_mul, ieee754sp_sub, );
1456DEF3OP(nmadd, sp, ieee754sp_mul, ieee754sp_add, ieee754sp_neg);
1457DEF3OP(nmsub, sp, ieee754sp_mul, ieee754sp_sub, ieee754sp_neg);
1458DEF3OP(madd, dp, ieee754dp_mul, ieee754dp_add, );
1459DEF3OP(msub, dp, ieee754dp_mul, ieee754dp_sub, );
1460DEF3OP(nmadd, dp, ieee754dp_mul, ieee754dp_add, ieee754dp_neg);
1461DEF3OP(nmsub, dp, ieee754dp_mul, ieee754dp_sub, ieee754dp_neg);
1462
1463static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
1464 mips_instruction ir, void __user **fault_addr)
1465{
1466 unsigned int rcsr = 0; /* resulting csr */
1467
1468 MIPS_FPU_EMU_INC_STATS(cp1xops);
1469
1470 switch (MIPSInst_FMA_FFMT(ir)) {
1471 case s_fmt:{ /* 0 */
1472
1473 union ieee754sp(*handler) (union ieee754sp, union ieee754sp, union ieee754sp);
1474 union ieee754sp fd, fr, fs, ft;
1475 u32 __user *va;
1476 u32 val;
1477
1478 switch (MIPSInst_FUNC(ir)) {
1479 case lwxc1_op:
1480 va = (void __user *) (xcp->regs[MIPSInst_FR(ir)] +
1481 xcp->regs[MIPSInst_FT(ir)]);
1482
1483 MIPS_FPU_EMU_INC_STATS(loads);
1484 if (!access_ok(va, sizeof(u32))) {
1485 MIPS_FPU_EMU_INC_STATS(errors);
1486 *fault_addr = va;
1487 return SIGBUS;
1488 }
1489 if (__get_user(val, va)) {
1490 MIPS_FPU_EMU_INC_STATS(errors);
1491 *fault_addr = va;
1492 return SIGSEGV;
1493 }
1494 SITOREG(val, MIPSInst_FD(ir));
1495 break;
1496
1497 case swxc1_op:
1498 va = (void __user *) (xcp->regs[MIPSInst_FR(ir)] +
1499 xcp->regs[MIPSInst_FT(ir)]);
1500
1501 MIPS_FPU_EMU_INC_STATS(stores);
1502
1503 SIFROMREG(val, MIPSInst_FS(ir));
1504 if (!access_ok(va, sizeof(u32))) {
1505 MIPS_FPU_EMU_INC_STATS(errors);
1506 *fault_addr = va;
1507 return SIGBUS;
1508 }
1509 if (put_user(val, va)) {
1510 MIPS_FPU_EMU_INC_STATS(errors);
1511 *fault_addr = va;
1512 return SIGSEGV;
1513 }
1514 break;
1515
1516 case madd_s_op:
1517 if (cpu_has_mac2008_only)
1518 handler = ieee754sp_madd;
1519 else
1520 handler = fpemu_sp_madd;
1521 goto scoptop;
1522 case msub_s_op:
1523 if (cpu_has_mac2008_only)
1524 handler = ieee754sp_msub;
1525 else
1526 handler = fpemu_sp_msub;
1527 goto scoptop;
1528 case nmadd_s_op:
1529 if (cpu_has_mac2008_only)
1530 handler = ieee754sp_nmadd;
1531 else
1532 handler = fpemu_sp_nmadd;
1533 goto scoptop;
1534 case nmsub_s_op:
1535 if (cpu_has_mac2008_only)
1536 handler = ieee754sp_nmsub;
1537 else
1538 handler = fpemu_sp_nmsub;
1539 goto scoptop;
1540
1541 scoptop:
1542 SPFROMREG(fr, MIPSInst_FR(ir));
1543 SPFROMREG(fs, MIPSInst_FS(ir));
1544 SPFROMREG(ft, MIPSInst_FT(ir));
1545 fd = (*handler) (fr, fs, ft);
1546 SPTOREG(fd, MIPSInst_FD(ir));
1547
1548 copcsr:
1549 if (ieee754_cxtest(IEEE754_INEXACT)) {
1550 MIPS_FPU_EMU_INC_STATS(ieee754_inexact);
1551 rcsr |= FPU_CSR_INE_X | FPU_CSR_INE_S;
1552 }
1553 if (ieee754_cxtest(IEEE754_UNDERFLOW)) {
1554 MIPS_FPU_EMU_INC_STATS(ieee754_underflow);
1555 rcsr |= FPU_CSR_UDF_X | FPU_CSR_UDF_S;
1556 }
1557 if (ieee754_cxtest(IEEE754_OVERFLOW)) {
1558 MIPS_FPU_EMU_INC_STATS(ieee754_overflow);
1559 rcsr |= FPU_CSR_OVF_X | FPU_CSR_OVF_S;
1560 }
1561 if (ieee754_cxtest(IEEE754_INVALID_OPERATION)) {
1562 MIPS_FPU_EMU_INC_STATS(ieee754_invalidop);
1563 rcsr |= FPU_CSR_INV_X | FPU_CSR_INV_S;
1564 }
1565
1566 ctx->fcr31 = (ctx->fcr31 & ~FPU_CSR_ALL_X) | rcsr;
1567 if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) {
1568 /*printk ("SIGFPE: FPU csr = %08x\n",
1569 ctx->fcr31); */
1570 return SIGFPE;
1571 }
1572
1573 break;
1574
1575 default:
1576 return SIGILL;
1577 }
1578 break;
1579 }
1580
1581 case d_fmt:{ /* 1 */
1582 union ieee754dp(*handler) (union ieee754dp, union ieee754dp, union ieee754dp);
1583 union ieee754dp fd, fr, fs, ft;
1584 u64 __user *va;
1585 u64 val;
1586
1587 switch (MIPSInst_FUNC(ir)) {
1588 case ldxc1_op:
1589 va = (void __user *) (xcp->regs[MIPSInst_FR(ir)] +
1590 xcp->regs[MIPSInst_FT(ir)]);
1591
1592 MIPS_FPU_EMU_INC_STATS(loads);
1593 if (!access_ok(va, sizeof(u64))) {
1594 MIPS_FPU_EMU_INC_STATS(errors);
1595 *fault_addr = va;
1596 return SIGBUS;
1597 }
1598 if (__get_user(val, va)) {
1599 MIPS_FPU_EMU_INC_STATS(errors);
1600 *fault_addr = va;
1601 return SIGSEGV;
1602 }
1603 DITOREG(val, MIPSInst_FD(ir));
1604 break;
1605
1606 case sdxc1_op:
1607 va = (void __user *) (xcp->regs[MIPSInst_FR(ir)] +
1608 xcp->regs[MIPSInst_FT(ir)]);
1609
1610 MIPS_FPU_EMU_INC_STATS(stores);
1611 DIFROMREG(val, MIPSInst_FS(ir));
1612 if (!access_ok(va, sizeof(u64))) {
1613 MIPS_FPU_EMU_INC_STATS(errors);
1614 *fault_addr = va;
1615 return SIGBUS;
1616 }
1617 if (__put_user(val, va)) {
1618 MIPS_FPU_EMU_INC_STATS(errors);
1619 *fault_addr = va;
1620 return SIGSEGV;
1621 }
1622 break;
1623
1624 case madd_d_op:
1625 if (cpu_has_mac2008_only)
1626 handler = ieee754dp_madd;
1627 else
1628 handler = fpemu_dp_madd;
1629 goto dcoptop;
1630 case msub_d_op:
1631 if (cpu_has_mac2008_only)
1632 handler = ieee754dp_msub;
1633 else
1634 handler = fpemu_dp_msub;
1635 goto dcoptop;
1636 case nmadd_d_op:
1637 if (cpu_has_mac2008_only)
1638 handler = ieee754dp_nmadd;
1639 else
1640 handler = fpemu_dp_nmadd;
1641 goto dcoptop;
1642 case nmsub_d_op:
1643 if (cpu_has_mac2008_only)
1644 handler = ieee754dp_nmsub;
1645 else
1646 handler = fpemu_dp_nmsub;
1647 goto dcoptop;
1648
1649 dcoptop:
1650 DPFROMREG(fr, MIPSInst_FR(ir));
1651 DPFROMREG(fs, MIPSInst_FS(ir));
1652 DPFROMREG(ft, MIPSInst_FT(ir));
1653 fd = (*handler) (fr, fs, ft);
1654 DPTOREG(fd, MIPSInst_FD(ir));
1655 goto copcsr;
1656
1657 default:
1658 return SIGILL;
1659 }
1660 break;
1661 }
1662
1663 case 0x3:
1664 if (MIPSInst_FUNC(ir) != pfetch_op)
1665 return SIGILL;
1666
1667 /* ignore prefx operation */
1668 break;
1669
1670 default:
1671 return SIGILL;
1672 }
1673
1674 return 0;
1675}
1676
1677
1678
1679/*
1680 * Emulate a single COP1 arithmetic instruction.
1681 */
1682static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
1683 mips_instruction ir)
1684{
1685 int rfmt; /* resulting format */
1686 unsigned int rcsr = 0; /* resulting csr */
1687 unsigned int oldrm;
1688 unsigned int cbit;
1689 unsigned int cond;
1690 union {
1691 union ieee754dp d;
1692 union ieee754sp s;
1693 int w;
1694 s64 l;
1695 } rv; /* resulting value */
1696 u64 bits;
1697
1698 MIPS_FPU_EMU_INC_STATS(cp1ops);
1699 switch (rfmt = (MIPSInst_FFMT(ir) & 0xf)) {
1700 case s_fmt: { /* 0 */
1701 union {
1702 union ieee754sp(*b) (union ieee754sp, union ieee754sp);
1703 union ieee754sp(*u) (union ieee754sp);
1704 } handler;
1705 union ieee754sp fd, fs, ft;
1706
1707 switch (MIPSInst_FUNC(ir)) {
1708 /* binary ops */
1709 case fadd_op:
1710 MIPS_FPU_EMU_INC_STATS(add_s);
1711 handler.b = ieee754sp_add;
1712 goto scopbop;
1713 case fsub_op:
1714 MIPS_FPU_EMU_INC_STATS(sub_s);
1715 handler.b = ieee754sp_sub;
1716 goto scopbop;
1717 case fmul_op:
1718 MIPS_FPU_EMU_INC_STATS(mul_s);
1719 handler.b = ieee754sp_mul;
1720 goto scopbop;
1721 case fdiv_op:
1722 MIPS_FPU_EMU_INC_STATS(div_s);
1723 handler.b = ieee754sp_div;
1724 goto scopbop;
1725
1726 /* unary ops */
1727 case fsqrt_op:
1728 if (!cpu_has_mips_2_3_4_5_r)
1729 return SIGILL;
1730
1731 MIPS_FPU_EMU_INC_STATS(sqrt_s);
1732 handler.u = ieee754sp_sqrt;
1733 goto scopuop;
1734
1735 /*
1736 * Note that on some MIPS IV implementations such as the
1737 * R5000 and R8000 the FSQRT and FRECIP instructions do not
1738 * achieve full IEEE-754 accuracy - however this emulator does.
1739 */
1740 case frsqrt_op:
1741 if (!cpu_has_mips_4_5_64_r2_r6)
1742 return SIGILL;
1743
1744 MIPS_FPU_EMU_INC_STATS(rsqrt_s);
1745 handler.u = fpemu_sp_rsqrt;
1746 goto scopuop;
1747
1748 case frecip_op:
1749 if (!cpu_has_mips_4_5_64_r2_r6)
1750 return SIGILL;
1751
1752 MIPS_FPU_EMU_INC_STATS(recip_s);
1753 handler.u = fpemu_sp_recip;
1754 goto scopuop;
1755
1756 case fmovc_op:
1757 if (!cpu_has_mips_4_5_r)
1758 return SIGILL;
1759
1760 cond = fpucondbit[MIPSInst_FT(ir) >> 2];
1761 if (((ctx->fcr31 & cond) != 0) !=
1762 ((MIPSInst_FT(ir) & 1) != 0))
1763 return 0;
1764 SPFROMREG(rv.s, MIPSInst_FS(ir));
1765 break;
1766
1767 case fmovz_op:
1768 if (!cpu_has_mips_4_5_r)
1769 return SIGILL;
1770
1771 if (xcp->regs[MIPSInst_FT(ir)] != 0)
1772 return 0;
1773 SPFROMREG(rv.s, MIPSInst_FS(ir));
1774 break;
1775
1776 case fmovn_op:
1777 if (!cpu_has_mips_4_5_r)
1778 return SIGILL;
1779
1780 if (xcp->regs[MIPSInst_FT(ir)] == 0)
1781 return 0;
1782 SPFROMREG(rv.s, MIPSInst_FS(ir));
1783 break;
1784
1785 case fseleqz_op:
1786 if (!cpu_has_mips_r6)
1787 return SIGILL;
1788
1789 MIPS_FPU_EMU_INC_STATS(seleqz_s);
1790 SPFROMREG(rv.s, MIPSInst_FT(ir));
1791 if (rv.w & 0x1)
1792 rv.w = 0;
1793 else
1794 SPFROMREG(rv.s, MIPSInst_FS(ir));
1795 break;
1796
1797 case fselnez_op:
1798 if (!cpu_has_mips_r6)
1799 return SIGILL;
1800
1801 MIPS_FPU_EMU_INC_STATS(selnez_s);
1802 SPFROMREG(rv.s, MIPSInst_FT(ir));
1803 if (rv.w & 0x1)
1804 SPFROMREG(rv.s, MIPSInst_FS(ir));
1805 else
1806 rv.w = 0;
1807 break;
1808
1809 case fmaddf_op: {
1810 union ieee754sp ft, fs, fd;
1811
1812 if (!cpu_has_mips_r6)
1813 return SIGILL;
1814
1815 MIPS_FPU_EMU_INC_STATS(maddf_s);
1816 SPFROMREG(ft, MIPSInst_FT(ir));
1817 SPFROMREG(fs, MIPSInst_FS(ir));
1818 SPFROMREG(fd, MIPSInst_FD(ir));
1819 rv.s = ieee754sp_maddf(fd, fs, ft);
1820 goto copcsr;
1821 }
1822
1823 case fmsubf_op: {
1824 union ieee754sp ft, fs, fd;
1825
1826 if (!cpu_has_mips_r6)
1827 return SIGILL;
1828
1829 MIPS_FPU_EMU_INC_STATS(msubf_s);
1830 SPFROMREG(ft, MIPSInst_FT(ir));
1831 SPFROMREG(fs, MIPSInst_FS(ir));
1832 SPFROMREG(fd, MIPSInst_FD(ir));
1833 rv.s = ieee754sp_msubf(fd, fs, ft);
1834 goto copcsr;
1835 }
1836
1837 case frint_op: {
1838 union ieee754sp fs;
1839
1840 if (!cpu_has_mips_r6)
1841 return SIGILL;
1842
1843 MIPS_FPU_EMU_INC_STATS(rint_s);
1844 SPFROMREG(fs, MIPSInst_FS(ir));
1845 rv.s = ieee754sp_rint(fs);
1846 goto copcsr;
1847 }
1848
1849 case fclass_op: {
1850 union ieee754sp fs;
1851
1852 if (!cpu_has_mips_r6)
1853 return SIGILL;
1854
1855 MIPS_FPU_EMU_INC_STATS(class_s);
1856 SPFROMREG(fs, MIPSInst_FS(ir));
1857 rv.w = ieee754sp_2008class(fs);
1858 rfmt = w_fmt;
1859 goto copcsr;
1860 }
1861
1862 case fmin_op: {
1863 union ieee754sp fs, ft;
1864
1865 if (!cpu_has_mips_r6)
1866 return SIGILL;
1867
1868 MIPS_FPU_EMU_INC_STATS(min_s);
1869 SPFROMREG(ft, MIPSInst_FT(ir));
1870 SPFROMREG(fs, MIPSInst_FS(ir));
1871 rv.s = ieee754sp_fmin(fs, ft);
1872 goto copcsr;
1873 }
1874
1875 case fmina_op: {
1876 union ieee754sp fs, ft;
1877
1878 if (!cpu_has_mips_r6)
1879 return SIGILL;
1880
1881 MIPS_FPU_EMU_INC_STATS(mina_s);
1882 SPFROMREG(ft, MIPSInst_FT(ir));
1883 SPFROMREG(fs, MIPSInst_FS(ir));
1884 rv.s = ieee754sp_fmina(fs, ft);
1885 goto copcsr;
1886 }
1887
1888 case fmax_op: {
1889 union ieee754sp fs, ft;
1890
1891 if (!cpu_has_mips_r6)
1892 return SIGILL;
1893
1894 MIPS_FPU_EMU_INC_STATS(max_s);
1895 SPFROMREG(ft, MIPSInst_FT(ir));
1896 SPFROMREG(fs, MIPSInst_FS(ir));
1897 rv.s = ieee754sp_fmax(fs, ft);
1898 goto copcsr;
1899 }
1900
1901 case fmaxa_op: {
1902 union ieee754sp fs, ft;
1903
1904 if (!cpu_has_mips_r6)
1905 return SIGILL;
1906
1907 MIPS_FPU_EMU_INC_STATS(maxa_s);
1908 SPFROMREG(ft, MIPSInst_FT(ir));
1909 SPFROMREG(fs, MIPSInst_FS(ir));
1910 rv.s = ieee754sp_fmaxa(fs, ft);
1911 goto copcsr;
1912 }
1913
1914 case fabs_op:
1915 MIPS_FPU_EMU_INC_STATS(abs_s);
1916 handler.u = ieee754sp_abs;
1917 goto scopuop;
1918
1919 case fneg_op:
1920 MIPS_FPU_EMU_INC_STATS(neg_s);
1921 handler.u = ieee754sp_neg;
1922 goto scopuop;
1923
1924 case fmov_op:
1925 /* an easy one */
1926 MIPS_FPU_EMU_INC_STATS(mov_s);
1927 SPFROMREG(rv.s, MIPSInst_FS(ir));
1928 goto copcsr;
1929
1930 /* binary op on handler */
1931scopbop:
1932 SPFROMREG(fs, MIPSInst_FS(ir));
1933 SPFROMREG(ft, MIPSInst_FT(ir));
1934
1935 rv.s = (*handler.b) (fs, ft);
1936 goto copcsr;
1937scopuop:
1938 SPFROMREG(fs, MIPSInst_FS(ir));
1939 rv.s = (*handler.u) (fs);
1940 goto copcsr;
1941copcsr:
1942 if (ieee754_cxtest(IEEE754_INEXACT)) {
1943 MIPS_FPU_EMU_INC_STATS(ieee754_inexact);
1944 rcsr |= FPU_CSR_INE_X | FPU_CSR_INE_S;
1945 }
1946 if (ieee754_cxtest(IEEE754_UNDERFLOW)) {
1947 MIPS_FPU_EMU_INC_STATS(ieee754_underflow);
1948 rcsr |= FPU_CSR_UDF_X | FPU_CSR_UDF_S;
1949 }
1950 if (ieee754_cxtest(IEEE754_OVERFLOW)) {
1951 MIPS_FPU_EMU_INC_STATS(ieee754_overflow);
1952 rcsr |= FPU_CSR_OVF_X | FPU_CSR_OVF_S;
1953 }
1954 if (ieee754_cxtest(IEEE754_ZERO_DIVIDE)) {
1955 MIPS_FPU_EMU_INC_STATS(ieee754_zerodiv);
1956 rcsr |= FPU_CSR_DIV_X | FPU_CSR_DIV_S;
1957 }
1958 if (ieee754_cxtest(IEEE754_INVALID_OPERATION)) {
1959 MIPS_FPU_EMU_INC_STATS(ieee754_invalidop);
1960 rcsr |= FPU_CSR_INV_X | FPU_CSR_INV_S;
1961 }
1962 break;
1963
1964 /* unary conv ops */
1965 case fcvts_op:
1966 return SIGILL; /* not defined */
1967
1968 case fcvtd_op:
1969 MIPS_FPU_EMU_INC_STATS(cvt_d_s);
1970 SPFROMREG(fs, MIPSInst_FS(ir));
1971 rv.d = ieee754dp_fsp(fs);
1972 rfmt = d_fmt;
1973 goto copcsr;
1974
1975 case fcvtw_op:
1976 MIPS_FPU_EMU_INC_STATS(cvt_w_s);
1977 SPFROMREG(fs, MIPSInst_FS(ir));
1978 rv.w = ieee754sp_tint(fs);
1979 rfmt = w_fmt;
1980 goto copcsr;
1981
1982 case fround_op:
1983 case ftrunc_op:
1984 case fceil_op:
1985 case ffloor_op:
1986 if (!cpu_has_mips_2_3_4_5_r)
1987 return SIGILL;
1988
1989 if (MIPSInst_FUNC(ir) == fceil_op)
1990 MIPS_FPU_EMU_INC_STATS(ceil_w_s);
1991 if (MIPSInst_FUNC(ir) == ffloor_op)
1992 MIPS_FPU_EMU_INC_STATS(floor_w_s);
1993 if (MIPSInst_FUNC(ir) == fround_op)
1994 MIPS_FPU_EMU_INC_STATS(round_w_s);
1995 if (MIPSInst_FUNC(ir) == ftrunc_op)
1996 MIPS_FPU_EMU_INC_STATS(trunc_w_s);
1997
1998 oldrm = ieee754_csr.rm;
1999 SPFROMREG(fs, MIPSInst_FS(ir));
2000 ieee754_csr.rm = MIPSInst_FUNC(ir);
2001 rv.w = ieee754sp_tint(fs);
2002 ieee754_csr.rm = oldrm;
2003 rfmt = w_fmt;
2004 goto copcsr;
2005
2006 case fsel_op:
2007 if (!cpu_has_mips_r6)
2008 return SIGILL;
2009
2010 MIPS_FPU_EMU_INC_STATS(sel_s);
2011 SPFROMREG(fd, MIPSInst_FD(ir));
2012 if (fd.bits & 0x1)
2013 SPFROMREG(rv.s, MIPSInst_FT(ir));
2014 else
2015 SPFROMREG(rv.s, MIPSInst_FS(ir));
2016 break;
2017
2018 case fcvtl_op:
2019 if (!cpu_has_mips_3_4_5_64_r2_r6)
2020 return SIGILL;
2021
2022 MIPS_FPU_EMU_INC_STATS(cvt_l_s);
2023 SPFROMREG(fs, MIPSInst_FS(ir));
2024 rv.l = ieee754sp_tlong(fs);
2025 rfmt = l_fmt;
2026 goto copcsr;
2027
2028 case froundl_op:
2029 case ftruncl_op:
2030 case fceill_op:
2031 case ffloorl_op:
2032 if (!cpu_has_mips_3_4_5_64_r2_r6)
2033 return SIGILL;
2034
2035 if (MIPSInst_FUNC(ir) == fceill_op)
2036 MIPS_FPU_EMU_INC_STATS(ceil_l_s);
2037 if (MIPSInst_FUNC(ir) == ffloorl_op)
2038 MIPS_FPU_EMU_INC_STATS(floor_l_s);
2039 if (MIPSInst_FUNC(ir) == froundl_op)
2040 MIPS_FPU_EMU_INC_STATS(round_l_s);
2041 if (MIPSInst_FUNC(ir) == ftruncl_op)
2042 MIPS_FPU_EMU_INC_STATS(trunc_l_s);
2043
2044 oldrm = ieee754_csr.rm;
2045 SPFROMREG(fs, MIPSInst_FS(ir));
2046 ieee754_csr.rm = MIPSInst_FUNC(ir);
2047 rv.l = ieee754sp_tlong(fs);
2048 ieee754_csr.rm = oldrm;
2049 rfmt = l_fmt;
2050 goto copcsr;
2051
2052 default:
2053 if (!NO_R6EMU && MIPSInst_FUNC(ir) >= fcmp_op) {
2054 unsigned int cmpop;
2055 union ieee754sp fs, ft;
2056
2057 cmpop = MIPSInst_FUNC(ir) - fcmp_op;
2058 SPFROMREG(fs, MIPSInst_FS(ir));
2059 SPFROMREG(ft, MIPSInst_FT(ir));
2060 rv.w = ieee754sp_cmp(fs, ft,
2061 cmptab[cmpop & 0x7], cmpop & 0x8);
2062 rfmt = -1;
2063 if ((cmpop & 0x8) && ieee754_cxtest
2064 (IEEE754_INVALID_OPERATION))
2065 rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S;
2066 else
2067 goto copcsr;
2068
2069 } else
2070 return SIGILL;
2071 break;
2072 }
2073 break;
2074 }
2075
2076 case d_fmt: {
2077 union ieee754dp fd, fs, ft;
2078 union {
2079 union ieee754dp(*b) (union ieee754dp, union ieee754dp);
2080 union ieee754dp(*u) (union ieee754dp);
2081 } handler;
2082
2083 switch (MIPSInst_FUNC(ir)) {
2084 /* binary ops */
2085 case fadd_op:
2086 MIPS_FPU_EMU_INC_STATS(add_d);
2087 handler.b = ieee754dp_add;
2088 goto dcopbop;
2089 case fsub_op:
2090 MIPS_FPU_EMU_INC_STATS(sub_d);
2091 handler.b = ieee754dp_sub;
2092 goto dcopbop;
2093 case fmul_op:
2094 MIPS_FPU_EMU_INC_STATS(mul_d);
2095 handler.b = ieee754dp_mul;
2096 goto dcopbop;
2097 case fdiv_op:
2098 MIPS_FPU_EMU_INC_STATS(div_d);
2099 handler.b = ieee754dp_div;
2100 goto dcopbop;
2101
2102 /* unary ops */
2103 case fsqrt_op:
2104 if (!cpu_has_mips_2_3_4_5_r)
2105 return SIGILL;
2106
2107 MIPS_FPU_EMU_INC_STATS(sqrt_d);
2108 handler.u = ieee754dp_sqrt;
2109 goto dcopuop;
2110 /*
2111 * Note that on some MIPS IV implementations such as the
2112 * R5000 and R8000 the FSQRT and FRECIP instructions do not
2113 * achieve full IEEE-754 accuracy - however this emulator does.
2114 */
2115 case frsqrt_op:
2116 if (!cpu_has_mips_4_5_64_r2_r6)
2117 return SIGILL;
2118
2119 MIPS_FPU_EMU_INC_STATS(rsqrt_d);
2120 handler.u = fpemu_dp_rsqrt;
2121 goto dcopuop;
2122 case frecip_op:
2123 if (!cpu_has_mips_4_5_64_r2_r6)
2124 return SIGILL;
2125
2126 MIPS_FPU_EMU_INC_STATS(recip_d);
2127 handler.u = fpemu_dp_recip;
2128 goto dcopuop;
2129 case fmovc_op:
2130 if (!cpu_has_mips_4_5_r)
2131 return SIGILL;
2132
2133 cond = fpucondbit[MIPSInst_FT(ir) >> 2];
2134 if (((ctx->fcr31 & cond) != 0) !=
2135 ((MIPSInst_FT(ir) & 1) != 0))
2136 return 0;
2137 DPFROMREG(rv.d, MIPSInst_FS(ir));
2138 break;
2139 case fmovz_op:
2140 if (!cpu_has_mips_4_5_r)
2141 return SIGILL;
2142
2143 if (xcp->regs[MIPSInst_FT(ir)] != 0)
2144 return 0;
2145 DPFROMREG(rv.d, MIPSInst_FS(ir));
2146 break;
2147 case fmovn_op:
2148 if (!cpu_has_mips_4_5_r)
2149 return SIGILL;
2150
2151 if (xcp->regs[MIPSInst_FT(ir)] == 0)
2152 return 0;
2153 DPFROMREG(rv.d, MIPSInst_FS(ir));
2154 break;
2155
2156 case fseleqz_op:
2157 if (!cpu_has_mips_r6)
2158 return SIGILL;
2159
2160 MIPS_FPU_EMU_INC_STATS(seleqz_d);
2161 DPFROMREG(rv.d, MIPSInst_FT(ir));
2162 if (rv.l & 0x1)
2163 rv.l = 0;
2164 else
2165 DPFROMREG(rv.d, MIPSInst_FS(ir));
2166 break;
2167
2168 case fselnez_op:
2169 if (!cpu_has_mips_r6)
2170 return SIGILL;
2171
2172 MIPS_FPU_EMU_INC_STATS(selnez_d);
2173 DPFROMREG(rv.d, MIPSInst_FT(ir));
2174 if (rv.l & 0x1)
2175 DPFROMREG(rv.d, MIPSInst_FS(ir));
2176 else
2177 rv.l = 0;
2178 break;
2179
2180 case fmaddf_op: {
2181 union ieee754dp ft, fs, fd;
2182
2183 if (!cpu_has_mips_r6)
2184 return SIGILL;
2185
2186 MIPS_FPU_EMU_INC_STATS(maddf_d);
2187 DPFROMREG(ft, MIPSInst_FT(ir));
2188 DPFROMREG(fs, MIPSInst_FS(ir));
2189 DPFROMREG(fd, MIPSInst_FD(ir));
2190 rv.d = ieee754dp_maddf(fd, fs, ft);
2191 goto copcsr;
2192 }
2193
2194 case fmsubf_op: {
2195 union ieee754dp ft, fs, fd;
2196
2197 if (!cpu_has_mips_r6)
2198 return SIGILL;
2199
2200 MIPS_FPU_EMU_INC_STATS(msubf_d);
2201 DPFROMREG(ft, MIPSInst_FT(ir));
2202 DPFROMREG(fs, MIPSInst_FS(ir));
2203 DPFROMREG(fd, MIPSInst_FD(ir));
2204 rv.d = ieee754dp_msubf(fd, fs, ft);
2205 goto copcsr;
2206 }
2207
2208 case frint_op: {
2209 union ieee754dp fs;
2210
2211 if (!cpu_has_mips_r6)
2212 return SIGILL;
2213
2214 MIPS_FPU_EMU_INC_STATS(rint_d);
2215 DPFROMREG(fs, MIPSInst_FS(ir));
2216 rv.d = ieee754dp_rint(fs);
2217 goto copcsr;
2218 }
2219
2220 case fclass_op: {
2221 union ieee754dp fs;
2222
2223 if (!cpu_has_mips_r6)
2224 return SIGILL;
2225
2226 MIPS_FPU_EMU_INC_STATS(class_d);
2227 DPFROMREG(fs, MIPSInst_FS(ir));
2228 rv.l = ieee754dp_2008class(fs);
2229 rfmt = l_fmt;
2230 goto copcsr;
2231 }
2232
2233 case fmin_op: {
2234 union ieee754dp fs, ft;
2235
2236 if (!cpu_has_mips_r6)
2237 return SIGILL;
2238
2239 MIPS_FPU_EMU_INC_STATS(min_d);
2240 DPFROMREG(ft, MIPSInst_FT(ir));
2241 DPFROMREG(fs, MIPSInst_FS(ir));
2242 rv.d = ieee754dp_fmin(fs, ft);
2243 goto copcsr;
2244 }
2245
2246 case fmina_op: {
2247 union ieee754dp fs, ft;
2248
2249 if (!cpu_has_mips_r6)
2250 return SIGILL;
2251
2252 MIPS_FPU_EMU_INC_STATS(mina_d);
2253 DPFROMREG(ft, MIPSInst_FT(ir));
2254 DPFROMREG(fs, MIPSInst_FS(ir));
2255 rv.d = ieee754dp_fmina(fs, ft);
2256 goto copcsr;
2257 }
2258
2259 case fmax_op: {
2260 union ieee754dp fs, ft;
2261
2262 if (!cpu_has_mips_r6)
2263 return SIGILL;
2264
2265 MIPS_FPU_EMU_INC_STATS(max_d);
2266 DPFROMREG(ft, MIPSInst_FT(ir));
2267 DPFROMREG(fs, MIPSInst_FS(ir));
2268 rv.d = ieee754dp_fmax(fs, ft);
2269 goto copcsr;
2270 }
2271
2272 case fmaxa_op: {
2273 union ieee754dp fs, ft;
2274
2275 if (!cpu_has_mips_r6)
2276 return SIGILL;
2277
2278 MIPS_FPU_EMU_INC_STATS(maxa_d);
2279 DPFROMREG(ft, MIPSInst_FT(ir));
2280 DPFROMREG(fs, MIPSInst_FS(ir));
2281 rv.d = ieee754dp_fmaxa(fs, ft);
2282 goto copcsr;
2283 }
2284
2285 case fabs_op:
2286 MIPS_FPU_EMU_INC_STATS(abs_d);
2287 handler.u = ieee754dp_abs;
2288 goto dcopuop;
2289
2290 case fneg_op:
2291 MIPS_FPU_EMU_INC_STATS(neg_d);
2292 handler.u = ieee754dp_neg;
2293 goto dcopuop;
2294
2295 case fmov_op:
2296 /* an easy one */
2297 MIPS_FPU_EMU_INC_STATS(mov_d);
2298 DPFROMREG(rv.d, MIPSInst_FS(ir));
2299 goto copcsr;
2300
2301 /* binary op on handler */
2302dcopbop:
2303 DPFROMREG(fs, MIPSInst_FS(ir));
2304 DPFROMREG(ft, MIPSInst_FT(ir));
2305
2306 rv.d = (*handler.b) (fs, ft);
2307 goto copcsr;
2308dcopuop:
2309 DPFROMREG(fs, MIPSInst_FS(ir));
2310 rv.d = (*handler.u) (fs);
2311 goto copcsr;
2312
2313 /*
2314 * unary conv ops
2315 */
2316 case fcvts_op:
2317 MIPS_FPU_EMU_INC_STATS(cvt_s_d);
2318 DPFROMREG(fs, MIPSInst_FS(ir));
2319 rv.s = ieee754sp_fdp(fs);
2320 rfmt = s_fmt;
2321 goto copcsr;
2322
2323 case fcvtd_op:
2324 return SIGILL; /* not defined */
2325
2326 case fcvtw_op:
2327 MIPS_FPU_EMU_INC_STATS(cvt_w_d);
2328 DPFROMREG(fs, MIPSInst_FS(ir));
2329 rv.w = ieee754dp_tint(fs); /* wrong */
2330 rfmt = w_fmt;
2331 goto copcsr;
2332
2333 case fround_op:
2334 case ftrunc_op:
2335 case fceil_op:
2336 case ffloor_op:
2337 if (!cpu_has_mips_2_3_4_5_r)
2338 return SIGILL;
2339
2340 if (MIPSInst_FUNC(ir) == fceil_op)
2341 MIPS_FPU_EMU_INC_STATS(ceil_w_d);
2342 if (MIPSInst_FUNC(ir) == ffloor_op)
2343 MIPS_FPU_EMU_INC_STATS(floor_w_d);
2344 if (MIPSInst_FUNC(ir) == fround_op)
2345 MIPS_FPU_EMU_INC_STATS(round_w_d);
2346 if (MIPSInst_FUNC(ir) == ftrunc_op)
2347 MIPS_FPU_EMU_INC_STATS(trunc_w_d);
2348
2349 oldrm = ieee754_csr.rm;
2350 DPFROMREG(fs, MIPSInst_FS(ir));
2351 ieee754_csr.rm = MIPSInst_FUNC(ir);
2352 rv.w = ieee754dp_tint(fs);
2353 ieee754_csr.rm = oldrm;
2354 rfmt = w_fmt;
2355 goto copcsr;
2356
2357 case fsel_op:
2358 if (!cpu_has_mips_r6)
2359 return SIGILL;
2360
2361 MIPS_FPU_EMU_INC_STATS(sel_d);
2362 DPFROMREG(fd, MIPSInst_FD(ir));
2363 if (fd.bits & 0x1)
2364 DPFROMREG(rv.d, MIPSInst_FT(ir));
2365 else
2366 DPFROMREG(rv.d, MIPSInst_FS(ir));
2367 break;
2368
2369 case fcvtl_op:
2370 if (!cpu_has_mips_3_4_5_64_r2_r6)
2371 return SIGILL;
2372
2373 MIPS_FPU_EMU_INC_STATS(cvt_l_d);
2374 DPFROMREG(fs, MIPSInst_FS(ir));
2375 rv.l = ieee754dp_tlong(fs);
2376 rfmt = l_fmt;
2377 goto copcsr;
2378
2379 case froundl_op:
2380 case ftruncl_op:
2381 case fceill_op:
2382 case ffloorl_op:
2383 if (!cpu_has_mips_3_4_5_64_r2_r6)
2384 return SIGILL;
2385
2386 if (MIPSInst_FUNC(ir) == fceill_op)
2387 MIPS_FPU_EMU_INC_STATS(ceil_l_d);
2388 if (MIPSInst_FUNC(ir) == ffloorl_op)
2389 MIPS_FPU_EMU_INC_STATS(floor_l_d);
2390 if (MIPSInst_FUNC(ir) == froundl_op)
2391 MIPS_FPU_EMU_INC_STATS(round_l_d);
2392 if (MIPSInst_FUNC(ir) == ftruncl_op)
2393 MIPS_FPU_EMU_INC_STATS(trunc_l_d);
2394
2395 oldrm = ieee754_csr.rm;
2396 DPFROMREG(fs, MIPSInst_FS(ir));
2397 ieee754_csr.rm = MIPSInst_FUNC(ir);
2398 rv.l = ieee754dp_tlong(fs);
2399 ieee754_csr.rm = oldrm;
2400 rfmt = l_fmt;
2401 goto copcsr;
2402
2403 default:
2404 if (!NO_R6EMU && MIPSInst_FUNC(ir) >= fcmp_op) {
2405 unsigned int cmpop;
2406 union ieee754dp fs, ft;
2407
2408 cmpop = MIPSInst_FUNC(ir) - fcmp_op;
2409 DPFROMREG(fs, MIPSInst_FS(ir));
2410 DPFROMREG(ft, MIPSInst_FT(ir));
2411 rv.w = ieee754dp_cmp(fs, ft,
2412 cmptab[cmpop & 0x7], cmpop & 0x8);
2413 rfmt = -1;
2414 if ((cmpop & 0x8)
2415 &&
2416 ieee754_cxtest
2417 (IEEE754_INVALID_OPERATION))
2418 rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S;
2419 else
2420 goto copcsr;
2421
2422 }
2423 else {
2424 return SIGILL;
2425 }
2426 break;
2427 }
2428 break;
2429 }
2430
2431 case w_fmt: {
2432 union ieee754dp fs;
2433
2434 switch (MIPSInst_FUNC(ir)) {
2435 case fcvts_op:
2436 /* convert word to single precision real */
2437 MIPS_FPU_EMU_INC_STATS(cvt_s_w);
2438 SPFROMREG(fs, MIPSInst_FS(ir));
2439 rv.s = ieee754sp_fint(fs.bits);
2440 rfmt = s_fmt;
2441 goto copcsr;
2442 case fcvtd_op:
2443 /* convert word to double precision real */
2444 MIPS_FPU_EMU_INC_STATS(cvt_d_w);
2445 SPFROMREG(fs, MIPSInst_FS(ir));
2446 rv.d = ieee754dp_fint(fs.bits);
2447 rfmt = d_fmt;
2448 goto copcsr;
2449 default: {
2450 /* Emulating the new CMP.condn.fmt R6 instruction */
2451#define CMPOP_MASK 0x7
2452#define SIGN_BIT (0x1 << 3)
2453#define PREDICATE_BIT (0x1 << 4)
2454
2455 int cmpop = MIPSInst_FUNC(ir) & CMPOP_MASK;
2456 int sig = MIPSInst_FUNC(ir) & SIGN_BIT;
2457 union ieee754sp fs, ft;
2458
2459 /* This is an R6 only instruction */
2460 if (!cpu_has_mips_r6 ||
2461 (MIPSInst_FUNC(ir) & 0x20))
2462 return SIGILL;
2463
2464 if (!sig) {
2465 if (!(MIPSInst_FUNC(ir) & PREDICATE_BIT)) {
2466 switch (cmpop) {
2467 case 0:
2468 MIPS_FPU_EMU_INC_STATS(cmp_af_s);
2469 break;
2470 case 1:
2471 MIPS_FPU_EMU_INC_STATS(cmp_un_s);
2472 break;
2473 case 2:
2474 MIPS_FPU_EMU_INC_STATS(cmp_eq_s);
2475 break;
2476 case 3:
2477 MIPS_FPU_EMU_INC_STATS(cmp_ueq_s);
2478 break;
2479 case 4:
2480 MIPS_FPU_EMU_INC_STATS(cmp_lt_s);
2481 break;
2482 case 5:
2483 MIPS_FPU_EMU_INC_STATS(cmp_ult_s);
2484 break;
2485 case 6:
2486 MIPS_FPU_EMU_INC_STATS(cmp_le_s);
2487 break;
2488 case 7:
2489 MIPS_FPU_EMU_INC_STATS(cmp_ule_s);
2490 break;
2491 }
2492 } else {
2493 switch (cmpop) {
2494 case 1:
2495 MIPS_FPU_EMU_INC_STATS(cmp_or_s);
2496 break;
2497 case 2:
2498 MIPS_FPU_EMU_INC_STATS(cmp_une_s);
2499 break;
2500 case 3:
2501 MIPS_FPU_EMU_INC_STATS(cmp_ne_s);
2502 break;
2503 }
2504 }
2505 } else {
2506 if (!(MIPSInst_FUNC(ir) & PREDICATE_BIT)) {
2507 switch (cmpop) {
2508 case 0:
2509 MIPS_FPU_EMU_INC_STATS(cmp_saf_s);
2510 break;
2511 case 1:
2512 MIPS_FPU_EMU_INC_STATS(cmp_sun_s);
2513 break;
2514 case 2:
2515 MIPS_FPU_EMU_INC_STATS(cmp_seq_s);
2516 break;
2517 case 3:
2518 MIPS_FPU_EMU_INC_STATS(cmp_sueq_s);
2519 break;
2520 case 4:
2521 MIPS_FPU_EMU_INC_STATS(cmp_slt_s);
2522 break;
2523 case 5:
2524 MIPS_FPU_EMU_INC_STATS(cmp_sult_s);
2525 break;
2526 case 6:
2527 MIPS_FPU_EMU_INC_STATS(cmp_sle_s);
2528 break;
2529 case 7:
2530 MIPS_FPU_EMU_INC_STATS(cmp_sule_s);
2531 break;
2532 }
2533 } else {
2534 switch (cmpop) {
2535 case 1:
2536 MIPS_FPU_EMU_INC_STATS(cmp_sor_s);
2537 break;
2538 case 2:
2539 MIPS_FPU_EMU_INC_STATS(cmp_sune_s);
2540 break;
2541 case 3:
2542 MIPS_FPU_EMU_INC_STATS(cmp_sne_s);
2543 break;
2544 }
2545 }
2546 }
2547
2548 /* fmt is w_fmt for single precision so fix it */
2549 rfmt = s_fmt;
2550 /* default to false */
2551 rv.w = 0;
2552
2553 /* CMP.condn.S */
2554 SPFROMREG(fs, MIPSInst_FS(ir));
2555 SPFROMREG(ft, MIPSInst_FT(ir));
2556
2557 /* positive predicates */
2558 if (!(MIPSInst_FUNC(ir) & PREDICATE_BIT)) {
2559 if (ieee754sp_cmp(fs, ft, cmptab[cmpop],
2560 sig))
2561 rv.w = -1; /* true, all 1s */
2562 if ((sig) &&
2563 ieee754_cxtest(IEEE754_INVALID_OPERATION))
2564 rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S;
2565 else
2566 goto copcsr;
2567 } else {
2568 /* negative predicates */
2569 switch (cmpop) {
2570 case 1:
2571 case 2:
2572 case 3:
2573 if (ieee754sp_cmp(fs, ft,
2574 negative_cmptab[cmpop],
2575 sig))
2576 rv.w = -1; /* true, all 1s */
2577 if (sig &&
2578 ieee754_cxtest(IEEE754_INVALID_OPERATION))
2579 rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S;
2580 else
2581 goto copcsr;
2582 break;
2583 default:
2584 /* Reserved R6 ops */
2585 return SIGILL;
2586 }
2587 }
2588 break;
2589 }
2590 }
2591 break;
2592 }
2593
2594 case l_fmt:
2595
2596 if (!cpu_has_mips_3_4_5_64_r2_r6)
2597 return SIGILL;
2598
2599 DIFROMREG(bits, MIPSInst_FS(ir));
2600
2601 switch (MIPSInst_FUNC(ir)) {
2602 case fcvts_op:
2603 /* convert long to single precision real */
2604 MIPS_FPU_EMU_INC_STATS(cvt_s_l);
2605 rv.s = ieee754sp_flong(bits);
2606 rfmt = s_fmt;
2607 goto copcsr;
2608 case fcvtd_op:
2609 /* convert long to double precision real */
2610 MIPS_FPU_EMU_INC_STATS(cvt_d_l);
2611 rv.d = ieee754dp_flong(bits);
2612 rfmt = d_fmt;
2613 goto copcsr;
2614 default: {
2615 /* Emulating the new CMP.condn.fmt R6 instruction */
2616 int cmpop = MIPSInst_FUNC(ir) & CMPOP_MASK;
2617 int sig = MIPSInst_FUNC(ir) & SIGN_BIT;
2618 union ieee754dp fs, ft;
2619
2620 if (!cpu_has_mips_r6 ||
2621 (MIPSInst_FUNC(ir) & 0x20))
2622 return SIGILL;
2623
2624 if (!sig) {
2625 if (!(MIPSInst_FUNC(ir) & PREDICATE_BIT)) {
2626 switch (cmpop) {
2627 case 0:
2628 MIPS_FPU_EMU_INC_STATS(cmp_af_d);
2629 break;
2630 case 1:
2631 MIPS_FPU_EMU_INC_STATS(cmp_un_d);
2632 break;
2633 case 2:
2634 MIPS_FPU_EMU_INC_STATS(cmp_eq_d);
2635 break;
2636 case 3:
2637 MIPS_FPU_EMU_INC_STATS(cmp_ueq_d);
2638 break;
2639 case 4:
2640 MIPS_FPU_EMU_INC_STATS(cmp_lt_d);
2641 break;
2642 case 5:
2643 MIPS_FPU_EMU_INC_STATS(cmp_ult_d);
2644 break;
2645 case 6:
2646 MIPS_FPU_EMU_INC_STATS(cmp_le_d);
2647 break;
2648 case 7:
2649 MIPS_FPU_EMU_INC_STATS(cmp_ule_d);
2650 break;
2651 }
2652 } else {
2653 switch (cmpop) {
2654 case 1:
2655 MIPS_FPU_EMU_INC_STATS(cmp_or_d);
2656 break;
2657 case 2:
2658 MIPS_FPU_EMU_INC_STATS(cmp_une_d);
2659 break;
2660 case 3:
2661 MIPS_FPU_EMU_INC_STATS(cmp_ne_d);
2662 break;
2663 }
2664 }
2665 } else {
2666 if (!(MIPSInst_FUNC(ir) & PREDICATE_BIT)) {
2667 switch (cmpop) {
2668 case 0:
2669 MIPS_FPU_EMU_INC_STATS(cmp_saf_d);
2670 break;
2671 case 1:
2672 MIPS_FPU_EMU_INC_STATS(cmp_sun_d);
2673 break;
2674 case 2:
2675 MIPS_FPU_EMU_INC_STATS(cmp_seq_d);
2676 break;
2677 case 3:
2678 MIPS_FPU_EMU_INC_STATS(cmp_sueq_d);
2679 break;
2680 case 4:
2681 MIPS_FPU_EMU_INC_STATS(cmp_slt_d);
2682 break;
2683 case 5:
2684 MIPS_FPU_EMU_INC_STATS(cmp_sult_d);
2685 break;
2686 case 6:
2687 MIPS_FPU_EMU_INC_STATS(cmp_sle_d);
2688 break;
2689 case 7:
2690 MIPS_FPU_EMU_INC_STATS(cmp_sule_d);
2691 break;
2692 }
2693 } else {
2694 switch (cmpop) {
2695 case 1:
2696 MIPS_FPU_EMU_INC_STATS(cmp_sor_d);
2697 break;
2698 case 2:
2699 MIPS_FPU_EMU_INC_STATS(cmp_sune_d);
2700 break;
2701 case 3:
2702 MIPS_FPU_EMU_INC_STATS(cmp_sne_d);
2703 break;
2704 }
2705 }
2706 }
2707
2708 /* fmt is l_fmt for double precision so fix it */
2709 rfmt = d_fmt;
2710 /* default to false */
2711 rv.l = 0;
2712
2713 /* CMP.condn.D */
2714 DPFROMREG(fs, MIPSInst_FS(ir));
2715 DPFROMREG(ft, MIPSInst_FT(ir));
2716
2717 /* positive predicates */
2718 if (!(MIPSInst_FUNC(ir) & PREDICATE_BIT)) {
2719 if (ieee754dp_cmp(fs, ft,
2720 cmptab[cmpop], sig))
2721 rv.l = -1LL; /* true, all 1s */
2722 if (sig &&
2723 ieee754_cxtest(IEEE754_INVALID_OPERATION))
2724 rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S;
2725 else
2726 goto copcsr;
2727 } else {
2728 /* negative predicates */
2729 switch (cmpop) {
2730 case 1:
2731 case 2:
2732 case 3:
2733 if (ieee754dp_cmp(fs, ft,
2734 negative_cmptab[cmpop],
2735 sig))
2736 rv.l = -1LL; /* true, all 1s */
2737 if (sig &&
2738 ieee754_cxtest(IEEE754_INVALID_OPERATION))
2739 rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S;
2740 else
2741 goto copcsr;
2742 break;
2743 default:
2744 /* Reserved R6 ops */
2745 return SIGILL;
2746 }
2747 }
2748 break;
2749 }
2750 }
2751 break;
2752
2753 default:
2754 return SIGILL;
2755 }
2756
2757 /*
2758 * Update the fpu CSR register for this operation.
2759 * If an exception is required, generate a tidy SIGFPE exception,
2760 * without updating the result register.
2761 * Note: cause exception bits do not accumulate, they are rewritten
2762 * for each op; only the flag/sticky bits accumulate.
2763 */
2764 ctx->fcr31 = (ctx->fcr31 & ~FPU_CSR_ALL_X) | rcsr;
2765 if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) {
2766 /*printk ("SIGFPE: FPU csr = %08x\n",ctx->fcr31); */
2767 return SIGFPE;
2768 }
2769
2770 /*
2771 * Now we can safely write the result back to the register file.
2772 */
2773 switch (rfmt) {
2774 case -1:
2775
2776 if (cpu_has_mips_4_5_r)
2777 cbit = fpucondbit[MIPSInst_FD(ir) >> 2];
2778 else
2779 cbit = FPU_CSR_COND;
2780 if (rv.w)
2781 ctx->fcr31 |= cbit;
2782 else
2783 ctx->fcr31 &= ~cbit;
2784 break;
2785
2786 case d_fmt:
2787 DPTOREG(rv.d, MIPSInst_FD(ir));
2788 break;
2789 case s_fmt:
2790 SPTOREG(rv.s, MIPSInst_FD(ir));
2791 break;
2792 case w_fmt:
2793 SITOREG(rv.w, MIPSInst_FD(ir));
2794 break;
2795 case l_fmt:
2796 if (!cpu_has_mips_3_4_5_64_r2_r6)
2797 return SIGILL;
2798
2799 DITOREG(rv.l, MIPSInst_FD(ir));
2800 break;
2801 default:
2802 return SIGILL;
2803 }
2804
2805 return 0;
2806}
2807
2808/*
2809 * Emulate FPU instructions.
2810 *
2811 * If we use FPU hardware, then we have been typically called to handle
2812 * an unimplemented operation, such as where an operand is a NaN or
2813 * denormalized. In that case exit the emulation loop after a single
2814 * iteration so as to let hardware execute any subsequent instructions.
2815 *
2816 * If we have no FPU hardware or it has been disabled, then continue
2817 * emulating floating-point instructions until one of these conditions
2818 * has occurred:
2819 *
2820 * - a non-FPU instruction has been encountered,
2821 *
2822 * - an attempt to emulate has ended with a signal,
2823 *
2824 * - the ISA mode has been switched.
2825 *
2826 * We need to terminate the emulation loop if we got switched to the
2827 * MIPS16 mode, whether supported or not, so that we do not attempt
2828 * to emulate a MIPS16 instruction as a regular MIPS FPU instruction.
2829 * Similarly if we got switched to the microMIPS mode and only the
2830 * regular MIPS mode is supported, so that we do not attempt to emulate
2831 * a microMIPS instruction as a regular MIPS FPU instruction. Or if
2832 * we got switched to the regular MIPS mode and only the microMIPS mode
2833 * is supported, so that we do not attempt to emulate a regular MIPS
2834 * instruction that should cause an Address Error exception instead.
2835 * For simplicity we always terminate upon an ISA mode switch.
2836 */
2837int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
2838 int has_fpu, void __user **fault_addr)
2839{
2840 unsigned long oldepc, prevepc;
2841 struct mm_decoded_insn dec_insn;
2842 u16 instr[4];
2843 u16 *instr_ptr;
2844 int sig = 0;
2845
2846 /*
2847 * Initialize context if it hasn't been used already, otherwise ensure
2848 * it has been saved to struct thread_struct.
2849 */
2850 if (!init_fp_ctx(current))
2851 lose_fpu(1);
2852
2853 oldepc = xcp->cp0_epc;
2854 do {
2855 prevepc = xcp->cp0_epc;
2856
2857 if (get_isa16_mode(prevepc) && cpu_has_mmips) {
2858 /*
2859 * Get next 2 microMIPS instructions and convert them
2860 * into 32-bit instructions.
2861 */
2862 if ((get_user(instr[0], (u16 __user *)msk_isa16_mode(xcp->cp0_epc))) ||
2863 (get_user(instr[1], (u16 __user *)msk_isa16_mode(xcp->cp0_epc + 2))) ||
2864 (get_user(instr[2], (u16 __user *)msk_isa16_mode(xcp->cp0_epc + 4))) ||
2865 (get_user(instr[3], (u16 __user *)msk_isa16_mode(xcp->cp0_epc + 6)))) {
2866 MIPS_FPU_EMU_INC_STATS(errors);
2867 return SIGBUS;
2868 }
2869 instr_ptr = instr;
2870
2871 /* Get first instruction. */
2872 if (mm_insn_16bit(*instr_ptr)) {
2873 /* Duplicate the half-word. */
2874 dec_insn.insn = (*instr_ptr << 16) |
2875 (*instr_ptr);
2876 /* 16-bit instruction. */
2877 dec_insn.pc_inc = 2;
2878 instr_ptr += 1;
2879 } else {
2880 dec_insn.insn = (*instr_ptr << 16) |
2881 *(instr_ptr+1);
2882 /* 32-bit instruction. */
2883 dec_insn.pc_inc = 4;
2884 instr_ptr += 2;
2885 }
2886 /* Get second instruction. */
2887 if (mm_insn_16bit(*instr_ptr)) {
2888 /* Duplicate the half-word. */
2889 dec_insn.next_insn = (*instr_ptr << 16) |
2890 (*instr_ptr);
2891 /* 16-bit instruction. */
2892 dec_insn.next_pc_inc = 2;
2893 } else {
2894 dec_insn.next_insn = (*instr_ptr << 16) |
2895 *(instr_ptr+1);
2896 /* 32-bit instruction. */
2897 dec_insn.next_pc_inc = 4;
2898 }
2899 dec_insn.micro_mips_mode = 1;
2900 } else {
2901 if ((get_user(dec_insn.insn,
2902 (mips_instruction __user *) xcp->cp0_epc)) ||
2903 (get_user(dec_insn.next_insn,
2904 (mips_instruction __user *)(xcp->cp0_epc+4)))) {
2905 MIPS_FPU_EMU_INC_STATS(errors);
2906 return SIGBUS;
2907 }
2908 dec_insn.pc_inc = 4;
2909 dec_insn.next_pc_inc = 4;
2910 dec_insn.micro_mips_mode = 0;
2911 }
2912
2913 if ((dec_insn.insn == 0) ||
2914 ((dec_insn.pc_inc == 2) &&
2915 ((dec_insn.insn & 0xffff) == MM_NOP16)))
2916 xcp->cp0_epc += dec_insn.pc_inc; /* Skip NOPs */
2917 else {
2918 /*
2919 * The 'ieee754_csr' is an alias of ctx->fcr31.
2920 * No need to copy ctx->fcr31 to ieee754_csr.
2921 */
2922 sig = cop1Emulate(xcp, ctx, dec_insn, fault_addr);
2923 }
2924
2925 if (has_fpu)
2926 break;
2927 if (sig)
2928 break;
2929 /*
2930 * We have to check for the ISA bit explicitly here,
2931 * because `get_isa16_mode' may return 0 if support
2932 * for code compression has been globally disabled,
2933 * or otherwise we may produce the wrong signal or
2934 * even proceed successfully where we must not.
2935 */
2936 if ((xcp->cp0_epc ^ prevepc) & 0x1)
2937 break;
2938
2939 cond_resched();
2940 } while (xcp->cp0_epc > prevepc);
2941
2942 /* SIGILL indicates a non-fpu instruction */
2943 if (sig == SIGILL && xcp->cp0_epc != oldepc)
2944 /* but if EPC has advanced, then ignore it */
2945 sig = 0;
2946
2947 return sig;
2948}
diff --git a/arch/mips/math-emu/dp_2008class.c b/arch/mips/math-emu/dp_2008class.c
new file mode 100644
index 000000000..81a0a63b1
--- /dev/null
+++ b/arch/mips/math-emu/dp_2008class.c
@@ -0,0 +1,52 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * IEEE754 floating point arithmetic
4 * double precision: CLASS.f
5 * FPR[fd] = class(FPR[fs])
6 *
7 * MIPS floating point support
8 * Copyright (C) 2015 Imagination Technologies, Ltd.
9 * Author: Markos Chandras <markos.chandras@imgtec.com>
10 */
11
12#include "ieee754dp.h"
13
14int ieee754dp_2008class(union ieee754dp x)
15{
16 COMPXDP;
17
18 EXPLODEXDP;
19
20 /*
21 * 10 bit mask as follows:
22 *
23 * bit0 = SNAN
24 * bit1 = QNAN
25 * bit2 = -INF
26 * bit3 = -NORM
27 * bit4 = -DNORM
28 * bit5 = -ZERO
29 * bit6 = INF
30 * bit7 = NORM
31 * bit8 = DNORM
32 * bit9 = ZERO
33 */
34
35 switch(xc) {
36 case IEEE754_CLASS_SNAN:
37 return 0x01;
38 case IEEE754_CLASS_QNAN:
39 return 0x02;
40 case IEEE754_CLASS_INF:
41 return 0x04 << (xs ? 0 : 4);
42 case IEEE754_CLASS_NORM:
43 return 0x08 << (xs ? 0 : 4);
44 case IEEE754_CLASS_DNORM:
45 return 0x10 << (xs ? 0 : 4);
46 case IEEE754_CLASS_ZERO:
47 return 0x20 << (xs ? 0 : 4);
48 default:
49 pr_err("Unknown class: %d\n", xc);
50 return 0;
51 }
52}
diff --git a/arch/mips/math-emu/dp_add.c b/arch/mips/math-emu/dp_add.c
new file mode 100644
index 000000000..78504736b
--- /dev/null
+++ b/arch/mips/math-emu/dp_add.c
@@ -0,0 +1,165 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/* IEEE754 floating point arithmetic
3 * double precision: common utilities
4 */
5/*
6 * MIPS floating point support
7 * Copyright (C) 1994-2000 Algorithmics Ltd.
8 */
9
10#include "ieee754dp.h"
11
12union ieee754dp ieee754dp_add(union ieee754dp x, union ieee754dp y)
13{
14 int s;
15
16 COMPXDP;
17 COMPYDP;
18
19 EXPLODEXDP;
20 EXPLODEYDP;
21
22 ieee754_clearcx();
23
24 FLUSHXDP;
25 FLUSHYDP;
26
27 switch (CLPAIR(xc, yc)) {
28 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
29 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
30 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
31 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
32 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
33 return ieee754dp_nanxcpt(y);
34
35 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
36 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
37 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
38 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
39 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
40 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
41 return ieee754dp_nanxcpt(x);
42
43 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
44 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
45 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
46 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
47 return y;
48
49 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
50 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
51 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
52 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
53 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
54 return x;
55
56
57 /*
58 * Infinity handling
59 */
60 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
61 if (xs == ys)
62 return x;
63 ieee754_setcx(IEEE754_INVALID_OPERATION);
64 return ieee754dp_indef();
65
66 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
67 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
68 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
69 return y;
70
71 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
72 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
73 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
74 return x;
75
76 /*
77 * Zero handling
78 */
79 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
80 if (xs == ys)
81 return x;
82 else
83 return ieee754dp_zero(ieee754_csr.rm == FPU_CSR_RD);
84
85 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
86 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
87 return x;
88
89 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
90 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
91 return y;
92
93 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
94 DPDNORMX;
95 fallthrough;
96 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
97 DPDNORMY;
98 break;
99
100 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
101 DPDNORMX;
102 break;
103
104 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM):
105 break;
106 }
107 assert(xm & DP_HIDDEN_BIT);
108 assert(ym & DP_HIDDEN_BIT);
109
110 /*
111 * Provide guard,round and stick bit space.
112 */
113 xm <<= 3;
114 ym <<= 3;
115
116 if (xe > ye) {
117 /*
118 * Have to shift y fraction right to align.
119 */
120 s = xe - ye;
121 ym = XDPSRS(ym, s);
122 ye += s;
123 } else if (ye > xe) {
124 /*
125 * Have to shift x fraction right to align.
126 */
127 s = ye - xe;
128 xm = XDPSRS(xm, s);
129 xe += s;
130 }
131 assert(xe == ye);
132 assert(xe <= DP_EMAX);
133
134 if (xs == ys) {
135 /*
136 * Generate 28 bit result of adding two 27 bit numbers
137 * leaving result in xm, xs and xe.
138 */
139 xm = xm + ym;
140
141 if (xm >> (DP_FBITS + 1 + 3)) { /* carry out */
142 xm = XDPSRS1(xm);
143 xe++;
144 }
145 } else {
146 if (xm >= ym) {
147 xm = xm - ym;
148 } else {
149 xm = ym - xm;
150 xs = ys;
151 }
152 if (xm == 0)
153 return ieee754dp_zero(ieee754_csr.rm == FPU_CSR_RD);
154
155 /*
156 * Normalize to rounding precision.
157 */
158 while ((xm >> (DP_FBITS + 3)) == 0) {
159 xm <<= 1;
160 xe--;
161 }
162 }
163
164 return ieee754dp_format(xs, xe, xm);
165}
diff --git a/arch/mips/math-emu/dp_cmp.c b/arch/mips/math-emu/dp_cmp.c
new file mode 100644
index 000000000..a59680b03
--- /dev/null
+++ b/arch/mips/math-emu/dp_cmp.c
@@ -0,0 +1,47 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/* IEEE754 floating point arithmetic
3 * double precision: common utilities
4 */
5/*
6 * MIPS floating point support
7 * Copyright (C) 1994-2000 Algorithmics Ltd.
8 */
9
10#include "ieee754dp.h"
11
12int ieee754dp_cmp(union ieee754dp x, union ieee754dp y, int cmp, int sig)
13{
14 s64 vx;
15 s64 vy;
16
17 COMPXDP;
18 COMPYDP;
19
20 EXPLODEXDP;
21 EXPLODEYDP;
22 FLUSHXDP;
23 FLUSHYDP;
24 ieee754_clearcx(); /* Even clear inexact flag here */
25
26 if (ieee754_class_nan(xc) || ieee754_class_nan(yc)) {
27 if (sig ||
28 xc == IEEE754_CLASS_SNAN || yc == IEEE754_CLASS_SNAN)
29 ieee754_setcx(IEEE754_INVALID_OPERATION);
30 return (cmp & IEEE754_CUN) != 0;
31 } else {
32 vx = x.bits;
33 vy = y.bits;
34
35 if (vx < 0)
36 vx = -vx ^ DP_SIGN_BIT;
37 if (vy < 0)
38 vy = -vy ^ DP_SIGN_BIT;
39
40 if (vx < vy)
41 return (cmp & IEEE754_CLT) != 0;
42 else if (vx == vy)
43 return (cmp & IEEE754_CEQ) != 0;
44 else
45 return (cmp & IEEE754_CGT) != 0;
46 }
47}
diff --git a/arch/mips/math-emu/dp_div.c b/arch/mips/math-emu/dp_div.c
new file mode 100644
index 000000000..ac1ecc462
--- /dev/null
+++ b/arch/mips/math-emu/dp_div.c
@@ -0,0 +1,143 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/* IEEE754 floating point arithmetic
3 * double precision: common utilities
4 */
5/*
6 * MIPS floating point support
7 * Copyright (C) 1994-2000 Algorithmics Ltd.
8 */
9
10#include "ieee754dp.h"
11
12union ieee754dp ieee754dp_div(union ieee754dp x, union ieee754dp y)
13{
14 u64 rm;
15 int re;
16 u64 bm;
17
18 COMPXDP;
19 COMPYDP;
20
21 EXPLODEXDP;
22 EXPLODEYDP;
23
24 ieee754_clearcx();
25
26 FLUSHXDP;
27 FLUSHYDP;
28
29 switch (CLPAIR(xc, yc)) {
30 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
31 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
32 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
33 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
34 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
35 return ieee754dp_nanxcpt(y);
36
37 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
38 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
39 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
40 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
41 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
42 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
43 return ieee754dp_nanxcpt(x);
44
45 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
46 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
47 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
48 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
49 return y;
50
51 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
52 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
53 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
54 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
55 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
56 return x;
57
58
59 /*
60 * Infinity handling
61 */
62 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
63 ieee754_setcx(IEEE754_INVALID_OPERATION);
64 return ieee754dp_indef();
65
66 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
67 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
68 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
69 return ieee754dp_zero(xs ^ ys);
70
71 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
72 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
73 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
74 return ieee754dp_inf(xs ^ ys);
75
76 /*
77 * Zero handling
78 */
79 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
80 ieee754_setcx(IEEE754_INVALID_OPERATION);
81 return ieee754dp_indef();
82
83 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
84 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
85 ieee754_setcx(IEEE754_ZERO_DIVIDE);
86 return ieee754dp_inf(xs ^ ys);
87
88 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
89 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
90 return ieee754dp_zero(xs == ys ? 0 : 1);
91
92 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
93 DPDNORMX;
94 fallthrough;
95 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
96 DPDNORMY;
97 break;
98
99 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
100 DPDNORMX;
101 break;
102
103 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM):
104 break;
105 }
106 assert(xm & DP_HIDDEN_BIT);
107 assert(ym & DP_HIDDEN_BIT);
108
109 /* provide rounding space */
110 xm <<= 3;
111 ym <<= 3;
112
113 /* now the dirty work */
114
115 rm = 0;
116 re = xe - ye;
117
118 for (bm = DP_MBIT(DP_FBITS + 2); bm; bm >>= 1) {
119 if (xm >= ym) {
120 xm -= ym;
121 rm |= bm;
122 if (xm == 0)
123 break;
124 }
125 xm <<= 1;
126 }
127
128 rm <<= 1;
129 if (xm)
130 rm |= 1; /* have remainder, set sticky */
131
132 assert(rm);
133
134 /*
135 * Normalise rm to rounding precision ?
136 */
137 while ((rm >> (DP_FBITS + 3)) == 0) {
138 rm <<= 1;
139 re--;
140 }
141
142 return ieee754dp_format(xs == ys ? 0 : 1, re, rm);
143}
diff --git a/arch/mips/math-emu/dp_fint.c b/arch/mips/math-emu/dp_fint.c
new file mode 100644
index 000000000..996b15ba0
--- /dev/null
+++ b/arch/mips/math-emu/dp_fint.c
@@ -0,0 +1,44 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/* IEEE754 floating point arithmetic
3 * double precision: common utilities
4 */
5/*
6 * MIPS floating point support
7 * Copyright (C) 1994-2000 Algorithmics Ltd.
8 */
9
10#include "ieee754dp.h"
11
12union ieee754dp ieee754dp_fint(int x)
13{
14 u64 xm;
15 int xe;
16 int xs;
17
18 ieee754_clearcx();
19
20 if (x == 0)
21 return ieee754dp_zero(0);
22 if (x == 1 || x == -1)
23 return ieee754dp_one(x < 0);
24 if (x == 10 || x == -10)
25 return ieee754dp_ten(x < 0);
26
27 xs = (x < 0);
28 if (xs) {
29 if (x == (1 << 31))
30 xm = ((unsigned) 1 << 31); /* max neg can't be safely negated */
31 else
32 xm = -x;
33 } else {
34 xm = x;
35 }
36
37 /* normalize - result can never be inexact or overflow */
38 xe = DP_FBITS;
39 while ((xm >> DP_FBITS) == 0) {
40 xm <<= 1;
41 xe--;
42 }
43 return builddp(xs, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT);
44}
diff --git a/arch/mips/math-emu/dp_flong.c b/arch/mips/math-emu/dp_flong.c
new file mode 100644
index 000000000..681ee00c9
--- /dev/null
+++ b/arch/mips/math-emu/dp_flong.c
@@ -0,0 +1,53 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/* IEEE754 floating point arithmetic
3 * double precision: common utilities
4 */
5/*
6 * MIPS floating point support
7 * Copyright (C) 1994-2000 Algorithmics Ltd.
8 */
9
10#include "ieee754dp.h"
11
12union ieee754dp ieee754dp_flong(s64 x)
13{
14 u64 xm;
15 int xe;
16 int xs;
17
18 ieee754_clearcx();
19
20 if (x == 0)
21 return ieee754dp_zero(0);
22 if (x == 1 || x == -1)
23 return ieee754dp_one(x < 0);
24 if (x == 10 || x == -10)
25 return ieee754dp_ten(x < 0);
26
27 xs = (x < 0);
28 if (xs) {
29 if (x == (1ULL << 63))
30 xm = (1ULL << 63); /* max neg can't be safely negated */
31 else
32 xm = -x;
33 } else {
34 xm = x;
35 }
36
37 /* normalize */
38 xe = DP_FBITS + 3;
39 if (xm >> (DP_FBITS + 1 + 3)) {
40 /* shunt out overflow bits */
41 while (xm >> (DP_FBITS + 1 + 3)) {
42 XDPSRSX1();
43 }
44 } else {
45 /* normalize in grs extended double precision */
46 while ((xm >> (DP_FBITS + 3)) == 0) {
47 xm <<= 1;
48 xe--;
49 }
50 }
51
52 return ieee754dp_format(xs, xe, xm);
53}
diff --git a/arch/mips/math-emu/dp_fmax.c b/arch/mips/math-emu/dp_fmax.c
new file mode 100644
index 000000000..126ec90bb
--- /dev/null
+++ b/arch/mips/math-emu/dp_fmax.c
@@ -0,0 +1,252 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * IEEE754 floating point arithmetic
4 * double precision: MIN{,A}.f
5 * MIN : Scalar Floating-Point Minimum
6 * MINA: Scalar Floating-Point argument with Minimum Absolute Value
7 *
8 * MIN.D : FPR[fd] = minNum(FPR[fs],FPR[ft])
9 * MINA.D: FPR[fd] = maxNumMag(FPR[fs],FPR[ft])
10 *
11 * MIPS floating point support
12 * Copyright (C) 2015 Imagination Technologies, Ltd.
13 * Author: Markos Chandras <markos.chandras@imgtec.com>
14 */
15
16#include "ieee754dp.h"
17
18union ieee754dp ieee754dp_fmax(union ieee754dp x, union ieee754dp y)
19{
20 COMPXDP;
21 COMPYDP;
22
23 EXPLODEXDP;
24 EXPLODEYDP;
25
26 FLUSHXDP;
27 FLUSHYDP;
28
29 ieee754_clearcx();
30
31 switch (CLPAIR(xc, yc)) {
32 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
33 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
34 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
35 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
36 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
37 return ieee754dp_nanxcpt(y);
38
39 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
40 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
41 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
42 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
43 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
44 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
45 return ieee754dp_nanxcpt(x);
46
47 /*
48 * Quiet NaN handling
49 */
50
51 /*
52 * The case of both inputs quiet NaNs
53 */
54 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
55 return x;
56
57 /*
58 * The cases of exactly one input quiet NaN (numbers
59 * are here preferred as returned values to NaNs)
60 */
61 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
62 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
63 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
64 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
65 return x;
66
67 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
68 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
69 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
70 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
71 return y;
72
73 /*
74 * Infinity and zero handling
75 */
76 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
77 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
78 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
79 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
80 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
81 return xs ? y : x;
82
83 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
84 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
85 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
86 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
87 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
88 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
89 return ys ? x : y;
90
91 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
92 return ieee754dp_zero(xs & ys);
93
94 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
95 DPDNORMX;
96 fallthrough;
97 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
98 DPDNORMY;
99 break;
100
101 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
102 DPDNORMX;
103 }
104
105 /* Finally get to do some computation */
106
107 assert(xm & DP_HIDDEN_BIT);
108 assert(ym & DP_HIDDEN_BIT);
109
110 /* Compare signs */
111 if (xs > ys)
112 return y;
113 else if (xs < ys)
114 return x;
115
116 /* Signs of inputs are equal, let's compare exponents */
117 if (xs == 0) {
118 /* Inputs are both positive */
119 if (xe > ye)
120 return x;
121 else if (xe < ye)
122 return y;
123 } else {
124 /* Inputs are both negative */
125 if (xe > ye)
126 return y;
127 else if (xe < ye)
128 return x;
129 }
130
131 /* Signs and exponents of inputs are equal, let's compare mantissas */
132 if (xs == 0) {
133 /* Inputs are both positive, with equal signs and exponents */
134 if (xm <= ym)
135 return y;
136 return x;
137 }
138 /* Inputs are both negative, with equal signs and exponents */
139 if (xm <= ym)
140 return x;
141 return y;
142}
143
144union ieee754dp ieee754dp_fmaxa(union ieee754dp x, union ieee754dp y)
145{
146 COMPXDP;
147 COMPYDP;
148
149 EXPLODEXDP;
150 EXPLODEYDP;
151
152 FLUSHXDP;
153 FLUSHYDP;
154
155 ieee754_clearcx();
156
157 switch (CLPAIR(xc, yc)) {
158 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
159 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
160 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
161 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
162 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
163 return ieee754dp_nanxcpt(y);
164
165 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
166 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
167 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
168 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
169 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
170 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
171 return ieee754dp_nanxcpt(x);
172
173 /*
174 * Quiet NaN handling
175 */
176
177 /*
178 * The case of both inputs quiet NaNs
179 */
180 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
181 return x;
182
183 /*
184 * The cases of exactly one input quiet NaN (numbers
185 * are here preferred as returned values to NaNs)
186 */
187 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
188 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
189 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
190 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
191 return x;
192
193 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
194 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
195 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
196 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
197 return y;
198
199 /*
200 * Infinity and zero handling
201 */
202 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
203 return ieee754dp_inf(xs & ys);
204
205 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
206 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
207 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
208 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
209 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
210 return x;
211
212 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
213 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
214 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
215 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
216 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
217 return y;
218
219 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
220 return ieee754dp_zero(xs & ys);
221
222 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
223 DPDNORMX;
224 fallthrough;
225 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
226 DPDNORMY;
227 break;
228
229 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
230 DPDNORMX;
231 }
232
233 /* Finally get to do some computation */
234
235 assert(xm & DP_HIDDEN_BIT);
236 assert(ym & DP_HIDDEN_BIT);
237
238 /* Compare exponent */
239 if (xe > ye)
240 return x;
241 else if (xe < ye)
242 return y;
243
244 /* Compare mantissa */
245 if (xm < ym)
246 return y;
247 else if (xm > ym)
248 return x;
249 else if (xs == 0)
250 return x;
251 return y;
252}
diff --git a/arch/mips/math-emu/dp_fmin.c b/arch/mips/math-emu/dp_fmin.c
new file mode 100644
index 000000000..35ded4c45
--- /dev/null
+++ b/arch/mips/math-emu/dp_fmin.c
@@ -0,0 +1,252 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * IEEE754 floating point arithmetic
4 * double precision: MIN{,A}.f
5 * MIN : Scalar Floating-Point Minimum
6 * MINA: Scalar Floating-Point argument with Minimum Absolute Value
7 *
8 * MIN.D : FPR[fd] = minNum(FPR[fs],FPR[ft])
9 * MINA.D: FPR[fd] = maxNumMag(FPR[fs],FPR[ft])
10 *
11 * MIPS floating point support
12 * Copyright (C) 2015 Imagination Technologies, Ltd.
13 * Author: Markos Chandras <markos.chandras@imgtec.com>
14 */
15
16#include "ieee754dp.h"
17
18union ieee754dp ieee754dp_fmin(union ieee754dp x, union ieee754dp y)
19{
20 COMPXDP;
21 COMPYDP;
22
23 EXPLODEXDP;
24 EXPLODEYDP;
25
26 FLUSHXDP;
27 FLUSHYDP;
28
29 ieee754_clearcx();
30
31 switch (CLPAIR(xc, yc)) {
32 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
33 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
34 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
35 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
36 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
37 return ieee754dp_nanxcpt(y);
38
39 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
40 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
41 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
42 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
43 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
44 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
45 return ieee754dp_nanxcpt(x);
46
47 /*
48 * Quiet NaN handling
49 */
50
51 /*
52 * The case of both inputs quiet NaNs
53 */
54 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
55 return x;
56
57 /*
58 * The cases of exactly one input quiet NaN (numbers
59 * are here preferred as returned values to NaNs)
60 */
61 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
62 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
63 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
64 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
65 return x;
66
67 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
68 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
69 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
70 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
71 return y;
72
73 /*
74 * Infinity and zero handling
75 */
76 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
77 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
78 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
79 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
80 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
81 return xs ? x : y;
82
83 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
84 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
85 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
86 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
87 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
88 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
89 return ys ? y : x;
90
91 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
92 return ieee754dp_zero(xs | ys);
93
94 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
95 DPDNORMX;
96 fallthrough;
97 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
98 DPDNORMY;
99 break;
100
101 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
102 DPDNORMX;
103 }
104
105 /* Finally get to do some computation */
106
107 assert(xm & DP_HIDDEN_BIT);
108 assert(ym & DP_HIDDEN_BIT);
109
110 /* Compare signs */
111 if (xs > ys)
112 return x;
113 else if (xs < ys)
114 return y;
115
116 /* Signs of inputs are the same, let's compare exponents */
117 if (xs == 0) {
118 /* Inputs are both positive */
119 if (xe > ye)
120 return y;
121 else if (xe < ye)
122 return x;
123 } else {
124 /* Inputs are both negative */
125 if (xe > ye)
126 return x;
127 else if (xe < ye)
128 return y;
129 }
130
131 /* Signs and exponents of inputs are equal, let's compare mantissas */
132 if (xs == 0) {
133 /* Inputs are both positive, with equal signs and exponents */
134 if (xm <= ym)
135 return x;
136 return y;
137 }
138 /* Inputs are both negative, with equal signs and exponents */
139 if (xm <= ym)
140 return y;
141 return x;
142}
143
144union ieee754dp ieee754dp_fmina(union ieee754dp x, union ieee754dp y)
145{
146 COMPXDP;
147 COMPYDP;
148
149 EXPLODEXDP;
150 EXPLODEYDP;
151
152 FLUSHXDP;
153 FLUSHYDP;
154
155 ieee754_clearcx();
156
157 switch (CLPAIR(xc, yc)) {
158 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
159 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
160 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
161 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
162 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
163 return ieee754dp_nanxcpt(y);
164
165 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
166 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
167 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
168 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
169 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
170 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
171 return ieee754dp_nanxcpt(x);
172
173 /*
174 * Quiet NaN handling
175 */
176
177 /*
178 * The case of both inputs quiet NaNs
179 */
180 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
181 return x;
182
183 /*
184 * The cases of exactly one input quiet NaN (numbers
185 * are here preferred as returned values to NaNs)
186 */
187 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
188 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
189 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
190 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
191 return x;
192
193 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
194 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
195 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
196 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
197 return y;
198
199 /*
200 * Infinity and zero handling
201 */
202 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
203 return ieee754dp_inf(xs | ys);
204
205 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
206 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
207 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
208 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
209 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
210 return y;
211
212 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
213 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
214 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
215 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
216 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
217 return x;
218
219 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
220 return ieee754dp_zero(xs | ys);
221
222 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
223 DPDNORMX;
224 fallthrough;
225 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
226 DPDNORMY;
227 break;
228
229 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
230 DPDNORMX;
231 }
232
233 /* Finally get to do some computation */
234
235 assert(xm & DP_HIDDEN_BIT);
236 assert(ym & DP_HIDDEN_BIT);
237
238 /* Compare exponent */
239 if (xe > ye)
240 return y;
241 else if (xe < ye)
242 return x;
243
244 /* Compare mantissa */
245 if (xm < ym)
246 return x;
247 else if (xm > ym)
248 return y;
249 else if (xs == 1)
250 return x;
251 return y;
252}
diff --git a/arch/mips/math-emu/dp_fsp.c b/arch/mips/math-emu/dp_fsp.c
new file mode 100644
index 000000000..be8a929c4
--- /dev/null
+++ b/arch/mips/math-emu/dp_fsp.c
@@ -0,0 +1,63 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/* IEEE754 floating point arithmetic
3 * double precision: common utilities
4 */
5/*
6 * MIPS floating point support
7 * Copyright (C) 1994-2000 Algorithmics Ltd.
8 */
9
10#include "ieee754sp.h"
11#include "ieee754dp.h"
12
13static inline union ieee754dp ieee754dp_nan_fsp(int xs, u64 xm)
14{
15 return builddp(xs, DP_EMAX + 1 + DP_EBIAS,
16 xm << (DP_FBITS - SP_FBITS));
17}
18
19union ieee754dp ieee754dp_fsp(union ieee754sp x)
20{
21 COMPXSP;
22
23 EXPLODEXSP;
24
25 ieee754_clearcx();
26
27 FLUSHXSP;
28
29 switch (xc) {
30 case IEEE754_CLASS_SNAN:
31 return ieee754dp_nanxcpt(ieee754dp_nan_fsp(xs, xm));
32
33 case IEEE754_CLASS_QNAN:
34 return ieee754dp_nan_fsp(xs, xm);
35
36 case IEEE754_CLASS_INF:
37 return ieee754dp_inf(xs);
38
39 case IEEE754_CLASS_ZERO:
40 return ieee754dp_zero(xs);
41
42 case IEEE754_CLASS_DNORM:
43 /* normalize */
44 while ((xm >> SP_FBITS) == 0) {
45 xm <<= 1;
46 xe--;
47 }
48 break;
49
50 case IEEE754_CLASS_NORM:
51 break;
52 }
53
54 /*
55 * Can't possibly overflow,underflow, or need rounding
56 */
57
58 /* drop the hidden bit */
59 xm &= ~SP_HIDDEN_BIT;
60
61 return builddp(xs, xe + DP_EBIAS,
62 (u64) xm << (DP_FBITS - SP_FBITS));
63}
diff --git a/arch/mips/math-emu/dp_maddf.c b/arch/mips/math-emu/dp_maddf.c
new file mode 100644
index 000000000..931e66f68
--- /dev/null
+++ b/arch/mips/math-emu/dp_maddf.c
@@ -0,0 +1,358 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * IEEE754 floating point arithmetic
4 * double precision: MADDF.f (Fused Multiply Add)
5 * MADDF.fmt: FPR[fd] = FPR[fd] + (FPR[fs] x FPR[ft])
6 *
7 * MIPS floating point support
8 * Copyright (C) 2015 Imagination Technologies, Ltd.
9 * Author: Markos Chandras <markos.chandras@imgtec.com>
10 */
11
12#include "ieee754dp.h"
13
14
15/* 128 bits shift right logical with rounding. */
16static void srl128(u64 *hptr, u64 *lptr, int count)
17{
18 u64 low;
19
20 if (count >= 128) {
21 *lptr = *hptr != 0 || *lptr != 0;
22 *hptr = 0;
23 } else if (count >= 64) {
24 if (count == 64) {
25 *lptr = *hptr | (*lptr != 0);
26 } else {
27 low = *lptr;
28 *lptr = *hptr >> (count - 64);
29 *lptr |= (*hptr << (128 - count)) != 0 || low != 0;
30 }
31 *hptr = 0;
32 } else {
33 low = *lptr;
34 *lptr = low >> count | *hptr << (64 - count);
35 *lptr |= (low << (64 - count)) != 0;
36 *hptr = *hptr >> count;
37 }
38}
39
40static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x,
41 union ieee754dp y, enum maddf_flags flags)
42{
43 int re;
44 int rs;
45 unsigned int lxm;
46 unsigned int hxm;
47 unsigned int lym;
48 unsigned int hym;
49 u64 lrm;
50 u64 hrm;
51 u64 lzm;
52 u64 hzm;
53 u64 t;
54 u64 at;
55 int s;
56
57 COMPXDP;
58 COMPYDP;
59 COMPZDP;
60
61 EXPLODEXDP;
62 EXPLODEYDP;
63 EXPLODEZDP;
64
65 FLUSHXDP;
66 FLUSHYDP;
67 FLUSHZDP;
68
69 ieee754_clearcx();
70
71 rs = xs ^ ys;
72 if (flags & MADDF_NEGATE_PRODUCT)
73 rs ^= 1;
74 if (flags & MADDF_NEGATE_ADDITION)
75 zs ^= 1;
76
77 /*
78 * Handle the cases when at least one of x, y or z is a NaN.
79 * Order of precedence is sNaN, qNaN and z, x, y.
80 */
81 if (zc == IEEE754_CLASS_SNAN)
82 return ieee754dp_nanxcpt(z);
83 if (xc == IEEE754_CLASS_SNAN)
84 return ieee754dp_nanxcpt(x);
85 if (yc == IEEE754_CLASS_SNAN)
86 return ieee754dp_nanxcpt(y);
87 if (zc == IEEE754_CLASS_QNAN)
88 return z;
89 if (xc == IEEE754_CLASS_QNAN)
90 return x;
91 if (yc == IEEE754_CLASS_QNAN)
92 return y;
93
94 if (zc == IEEE754_CLASS_DNORM)
95 DPDNORMZ;
96 /* ZERO z cases are handled separately below */
97
98 switch (CLPAIR(xc, yc)) {
99
100 /*
101 * Infinity handling
102 */
103 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
104 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
105 ieee754_setcx(IEEE754_INVALID_OPERATION);
106 return ieee754dp_indef();
107
108 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
109 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
110 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
111 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
112 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
113 if ((zc == IEEE754_CLASS_INF) && (zs != rs)) {
114 /*
115 * Cases of addition of infinities with opposite signs
116 * or subtraction of infinities with same signs.
117 */
118 ieee754_setcx(IEEE754_INVALID_OPERATION);
119 return ieee754dp_indef();
120 }
121 /*
122 * z is here either not an infinity, or an infinity having the
123 * same sign as product (x*y). The result must be an infinity,
124 * and its sign is determined only by the sign of product (x*y).
125 */
126 return ieee754dp_inf(rs);
127
128 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
129 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
130 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
131 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
132 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
133 if (zc == IEEE754_CLASS_INF)
134 return ieee754dp_inf(zs);
135 if (zc == IEEE754_CLASS_ZERO) {
136 /* Handle cases +0 + (-0) and similar ones. */
137 if (zs == rs)
138 /*
139 * Cases of addition of zeros of equal signs
140 * or subtraction of zeroes of opposite signs.
141 * The sign of the resulting zero is in any
142 * such case determined only by the sign of z.
143 */
144 return z;
145
146 return ieee754dp_zero(ieee754_csr.rm == FPU_CSR_RD);
147 }
148 /* x*y is here 0, and z is not 0, so just return z */
149 return z;
150
151 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
152 DPDNORMX;
153 fallthrough;
154 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
155 if (zc == IEEE754_CLASS_INF)
156 return ieee754dp_inf(zs);
157 DPDNORMY;
158 break;
159
160 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
161 if (zc == IEEE754_CLASS_INF)
162 return ieee754dp_inf(zs);
163 DPDNORMX;
164 break;
165
166 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM):
167 if (zc == IEEE754_CLASS_INF)
168 return ieee754dp_inf(zs);
169 /* continue to real computations */
170 }
171
172 /* Finally get to do some computation */
173
174 /*
175 * Do the multiplication bit first
176 *
177 * rm = xm * ym, re = xe + ye basically
178 *
179 * At this point xm and ym should have been normalized.
180 */
181 assert(xm & DP_HIDDEN_BIT);
182 assert(ym & DP_HIDDEN_BIT);
183
184 re = xe + ye;
185
186 /* shunt to top of word */
187 xm <<= 64 - (DP_FBITS + 1);
188 ym <<= 64 - (DP_FBITS + 1);
189
190 /*
191 * Multiply 64 bits xm and ym to give 128 bits result in hrm:lrm.
192 */
193
194 lxm = xm;
195 hxm = xm >> 32;
196 lym = ym;
197 hym = ym >> 32;
198
199 lrm = DPXMULT(lxm, lym);
200 hrm = DPXMULT(hxm, hym);
201
202 t = DPXMULT(lxm, hym);
203
204 at = lrm + (t << 32);
205 hrm += at < lrm;
206 lrm = at;
207
208 hrm = hrm + (t >> 32);
209
210 t = DPXMULT(hxm, lym);
211
212 at = lrm + (t << 32);
213 hrm += at < lrm;
214 lrm = at;
215
216 hrm = hrm + (t >> 32);
217
218 /* Put explicit bit at bit 126 if necessary */
219 if ((int64_t)hrm < 0) {
220 lrm = (hrm << 63) | (lrm >> 1);
221 hrm = hrm >> 1;
222 re++;
223 }
224
225 assert(hrm & (1 << 62));
226
227 if (zc == IEEE754_CLASS_ZERO) {
228 /*
229 * Move explicit bit from bit 126 to bit 55 since the
230 * ieee754dp_format code expects the mantissa to be
231 * 56 bits wide (53 + 3 rounding bits).
232 */
233 srl128(&hrm, &lrm, (126 - 55));
234 return ieee754dp_format(rs, re, lrm);
235 }
236
237 /* Move explicit bit from bit 52 to bit 126 */
238 lzm = 0;
239 hzm = zm << 10;
240 assert(hzm & (1 << 62));
241
242 /* Make the exponents the same */
243 if (ze > re) {
244 /*
245 * Have to shift y fraction right to align.
246 */
247 s = ze - re;
248 srl128(&hrm, &lrm, s);
249 re += s;
250 } else if (re > ze) {
251 /*
252 * Have to shift x fraction right to align.
253 */
254 s = re - ze;
255 srl128(&hzm, &lzm, s);
256 ze += s;
257 }
258 assert(ze == re);
259 assert(ze <= DP_EMAX);
260
261 /* Do the addition */
262 if (zs == rs) {
263 /*
264 * Generate 128 bit result by adding two 127 bit numbers
265 * leaving result in hzm:lzm, zs and ze.
266 */
267 hzm = hzm + hrm + (lzm > (lzm + lrm));
268 lzm = lzm + lrm;
269 if ((int64_t)hzm < 0) { /* carry out */
270 srl128(&hzm, &lzm, 1);
271 ze++;
272 }
273 } else {
274 if (hzm > hrm || (hzm == hrm && lzm >= lrm)) {
275 hzm = hzm - hrm - (lzm < lrm);
276 lzm = lzm - lrm;
277 } else {
278 hzm = hrm - hzm - (lrm < lzm);
279 lzm = lrm - lzm;
280 zs = rs;
281 }
282 if (lzm == 0 && hzm == 0)
283 return ieee754dp_zero(ieee754_csr.rm == FPU_CSR_RD);
284
285 /*
286 * Put explicit bit at bit 126 if necessary.
287 */
288 if (hzm == 0) {
289 /* left shift by 63 or 64 bits */
290 if ((int64_t)lzm < 0) {
291 /* MSB of lzm is the explicit bit */
292 hzm = lzm >> 1;
293 lzm = lzm << 63;
294 ze -= 63;
295 } else {
296 hzm = lzm;
297 lzm = 0;
298 ze -= 64;
299 }
300 }
301
302 t = 0;
303 while ((hzm >> (62 - t)) == 0)
304 t++;
305
306 assert(t <= 62);
307 if (t) {
308 hzm = hzm << t | lzm >> (64 - t);
309 lzm = lzm << t;
310 ze -= t;
311 }
312 }
313
314 /*
315 * Move explicit bit from bit 126 to bit 55 since the
316 * ieee754dp_format code expects the mantissa to be
317 * 56 bits wide (53 + 3 rounding bits).
318 */
319 srl128(&hzm, &lzm, (126 - 55));
320
321 return ieee754dp_format(zs, ze, lzm);
322}
323
324union ieee754dp ieee754dp_maddf(union ieee754dp z, union ieee754dp x,
325 union ieee754dp y)
326{
327 return _dp_maddf(z, x, y, 0);
328}
329
330union ieee754dp ieee754dp_msubf(union ieee754dp z, union ieee754dp x,
331 union ieee754dp y)
332{
333 return _dp_maddf(z, x, y, MADDF_NEGATE_PRODUCT);
334}
335
336union ieee754dp ieee754dp_madd(union ieee754dp z, union ieee754dp x,
337 union ieee754dp y)
338{
339 return _dp_maddf(z, x, y, 0);
340}
341
342union ieee754dp ieee754dp_msub(union ieee754dp z, union ieee754dp x,
343 union ieee754dp y)
344{
345 return _dp_maddf(z, x, y, MADDF_NEGATE_ADDITION);
346}
347
348union ieee754dp ieee754dp_nmadd(union ieee754dp z, union ieee754dp x,
349 union ieee754dp y)
350{
351 return _dp_maddf(z, x, y, MADDF_NEGATE_PRODUCT|MADDF_NEGATE_ADDITION);
352}
353
354union ieee754dp ieee754dp_nmsub(union ieee754dp z, union ieee754dp x,
355 union ieee754dp y)
356{
357 return _dp_maddf(z, x, y, MADDF_NEGATE_PRODUCT);
358}
diff --git a/arch/mips/math-emu/dp_mul.c b/arch/mips/math-emu/dp_mul.c
new file mode 100644
index 000000000..8a671bb7a
--- /dev/null
+++ b/arch/mips/math-emu/dp_mul.c
@@ -0,0 +1,159 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/* IEEE754 floating point arithmetic
3 * double precision: common utilities
4 */
5/*
6 * MIPS floating point support
7 * Copyright (C) 1994-2000 Algorithmics Ltd.
8 */
9
10#include "ieee754dp.h"
11
12union ieee754dp ieee754dp_mul(union ieee754dp x, union ieee754dp y)
13{
14 int re;
15 int rs;
16 u64 rm;
17 unsigned int lxm;
18 unsigned int hxm;
19 unsigned int lym;
20 unsigned int hym;
21 u64 lrm;
22 u64 hrm;
23 u64 t;
24 u64 at;
25
26 COMPXDP;
27 COMPYDP;
28
29 EXPLODEXDP;
30 EXPLODEYDP;
31
32 ieee754_clearcx();
33
34 FLUSHXDP;
35 FLUSHYDP;
36
37 switch (CLPAIR(xc, yc)) {
38 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
39 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
40 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
41 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
42 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
43 return ieee754dp_nanxcpt(y);
44
45 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
46 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
47 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
48 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
49 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
50 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
51 return ieee754dp_nanxcpt(x);
52
53 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
54 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
55 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
56 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
57 return y;
58
59 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
60 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
61 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
62 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
63 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
64 return x;
65
66
67 /*
68 * Infinity handling
69 */
70 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
71 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
72 ieee754_setcx(IEEE754_INVALID_OPERATION);
73 return ieee754dp_indef();
74
75 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
76 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
77 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
78 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
79 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
80 return ieee754dp_inf(xs ^ ys);
81
82 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
83 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
84 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
85 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
86 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
87 return ieee754dp_zero(xs ^ ys);
88
89
90 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
91 DPDNORMX;
92 fallthrough;
93 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
94 DPDNORMY;
95 break;
96
97 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
98 DPDNORMX;
99 break;
100
101 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM):
102 break;
103 }
104 /* rm = xm * ym, re = xe+ye basically */
105 assert(xm & DP_HIDDEN_BIT);
106 assert(ym & DP_HIDDEN_BIT);
107
108 re = xe + ye;
109 rs = xs ^ ys;
110
111 /* shunt to top of word */
112 xm <<= 64 - (DP_FBITS + 1);
113 ym <<= 64 - (DP_FBITS + 1);
114
115 /*
116 * Multiply 64 bits xm, ym to give high 64 bits rm with stickness.
117 */
118
119 lxm = xm;
120 hxm = xm >> 32;
121 lym = ym;
122 hym = ym >> 32;
123
124 lrm = DPXMULT(lxm, lym);
125 hrm = DPXMULT(hxm, hym);
126
127 t = DPXMULT(lxm, hym);
128
129 at = lrm + (t << 32);
130 hrm += at < lrm;
131 lrm = at;
132
133 hrm = hrm + (t >> 32);
134
135 t = DPXMULT(hxm, lym);
136
137 at = lrm + (t << 32);
138 hrm += at < lrm;
139 lrm = at;
140
141 hrm = hrm + (t >> 32);
142
143 rm = hrm | (lrm != 0);
144
145 /*
146 * Sticky shift down to normal rounding precision.
147 */
148 if ((s64) rm < 0) {
149 rm = (rm >> (64 - (DP_FBITS + 1 + 3))) |
150 ((rm << (DP_FBITS + 1 + 3)) != 0);
151 re++;
152 } else {
153 rm = (rm >> (64 - (DP_FBITS + 1 + 3 + 1))) |
154 ((rm << (DP_FBITS + 1 + 3 + 1)) != 0);
155 }
156 assert(rm & (DP_HIDDEN_BIT << 3));
157
158 return ieee754dp_format(rs, re, rm);
159}
diff --git a/arch/mips/math-emu/dp_rint.c b/arch/mips/math-emu/dp_rint.c
new file mode 100644
index 000000000..7f30b7a30
--- /dev/null
+++ b/arch/mips/math-emu/dp_rint.c
@@ -0,0 +1,78 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/* IEEE754 floating point arithmetic
3 * double precision: common utilities
4 */
5/*
6 * MIPS floating point support
7 * Copyright (C) 1994-2000 Algorithmics Ltd.
8 * Copyright (C) 2017 Imagination Technologies, Ltd.
9 * Author: Aleksandar Markovic <aleksandar.markovic@imgtec.com>
10 */
11
12#include "ieee754dp.h"
13
14union ieee754dp ieee754dp_rint(union ieee754dp x)
15{
16 union ieee754dp ret;
17 u64 residue;
18 int sticky;
19 int round;
20 int odd;
21
22 COMPXDP;
23
24 ieee754_clearcx();
25
26 EXPLODEXDP;
27 FLUSHXDP;
28
29 if (xc == IEEE754_CLASS_SNAN)
30 return ieee754dp_nanxcpt(x);
31
32 if ((xc == IEEE754_CLASS_QNAN) ||
33 (xc == IEEE754_CLASS_INF) ||
34 (xc == IEEE754_CLASS_ZERO))
35 return x;
36
37 if (xe >= DP_FBITS)
38 return x;
39
40 if (xe < -1) {
41 residue = xm;
42 round = 0;
43 sticky = residue != 0;
44 xm = 0;
45 } else {
46 residue = xm << (64 - DP_FBITS + xe);
47 round = (residue >> 63) != 0;
48 sticky = (residue << 1) != 0;
49 xm >>= DP_FBITS - xe;
50 }
51
52 odd = (xm & 0x1) != 0x0;
53
54 switch (ieee754_csr.rm) {
55 case FPU_CSR_RN: /* toward nearest */
56 if (round && (sticky || odd))
57 xm++;
58 break;
59 case FPU_CSR_RZ: /* toward zero */
60 break;
61 case FPU_CSR_RU: /* toward +infinity */
62 if ((round || sticky) && !xs)
63 xm++;
64 break;
65 case FPU_CSR_RD: /* toward -infinity */
66 if ((round || sticky) && xs)
67 xm++;
68 break;
69 }
70
71 if (round || sticky)
72 ieee754_setcx(IEEE754_INEXACT);
73
74 ret = ieee754dp_flong(xm);
75 DPSIGN(ret) = xs;
76
77 return ret;
78}
diff --git a/arch/mips/math-emu/dp_simple.c b/arch/mips/math-emu/dp_simple.c
new file mode 100644
index 000000000..b063aad7d
--- /dev/null
+++ b/arch/mips/math-emu/dp_simple.c
@@ -0,0 +1,49 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/* IEEE754 floating point arithmetic
3 * double precision: common utilities
4 */
5/*
6 * MIPS floating point support
7 * Copyright (C) 1994-2000 Algorithmics Ltd.
8 */
9
10#include "ieee754dp.h"
11
12union ieee754dp ieee754dp_neg(union ieee754dp x)
13{
14 union ieee754dp y;
15
16 if (ieee754_csr.abs2008) {
17 y = x;
18 DPSIGN(y) = !DPSIGN(x);
19 } else {
20 unsigned int oldrm;
21
22 oldrm = ieee754_csr.rm;
23 ieee754_csr.rm = FPU_CSR_RD;
24 y = ieee754dp_sub(ieee754dp_zero(0), x);
25 ieee754_csr.rm = oldrm;
26 }
27 return y;
28}
29
30union ieee754dp ieee754dp_abs(union ieee754dp x)
31{
32 union ieee754dp y;
33
34 if (ieee754_csr.abs2008) {
35 y = x;
36 DPSIGN(y) = 0;
37 } else {
38 unsigned int oldrm;
39
40 oldrm = ieee754_csr.rm;
41 ieee754_csr.rm = FPU_CSR_RD;
42 if (DPSIGN(x))
43 y = ieee754dp_sub(ieee754dp_zero(0), x);
44 else
45 y = ieee754dp_add(ieee754dp_zero(0), x);
46 ieee754_csr.rm = oldrm;
47 }
48 return y;
49}
diff --git a/arch/mips/math-emu/dp_sqrt.c b/arch/mips/math-emu/dp_sqrt.c
new file mode 100644
index 000000000..1ee38f824
--- /dev/null
+++ b/arch/mips/math-emu/dp_sqrt.c
@@ -0,0 +1,152 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/* IEEE754 floating point arithmetic
3 * double precision square root
4 */
5/*
6 * MIPS floating point support
7 * Copyright (C) 1994-2000 Algorithmics Ltd.
8 */
9
10#include "ieee754dp.h"
11
12static const unsigned int table[] = {
13 0, 1204, 3062, 5746, 9193, 13348, 18162, 23592,
14 29598, 36145, 43202, 50740, 58733, 67158, 75992,
15 85215, 83599, 71378, 60428, 50647, 41945, 34246,
16 27478, 21581, 16499, 12183, 8588, 5674, 3403,
17 1742, 661, 130
18};
19
20union ieee754dp ieee754dp_sqrt(union ieee754dp x)
21{
22 struct _ieee754_csr oldcsr;
23 union ieee754dp y, z, t;
24 unsigned int scalx, yh;
25 COMPXDP;
26
27 EXPLODEXDP;
28 ieee754_clearcx();
29 FLUSHXDP;
30
31 /* x == INF or NAN? */
32 switch (xc) {
33 case IEEE754_CLASS_SNAN:
34 return ieee754dp_nanxcpt(x);
35
36 case IEEE754_CLASS_QNAN:
37 /* sqrt(Nan) = Nan */
38 return x;
39
40 case IEEE754_CLASS_ZERO:
41 /* sqrt(0) = 0 */
42 return x;
43
44 case IEEE754_CLASS_INF:
45 if (xs) {
46 /* sqrt(-Inf) = Nan */
47 ieee754_setcx(IEEE754_INVALID_OPERATION);
48 return ieee754dp_indef();
49 }
50 /* sqrt(+Inf) = Inf */
51 return x;
52
53 case IEEE754_CLASS_DNORM:
54 DPDNORMX;
55 fallthrough;
56 case IEEE754_CLASS_NORM:
57 if (xs) {
58 /* sqrt(-x) = Nan */
59 ieee754_setcx(IEEE754_INVALID_OPERATION);
60 return ieee754dp_indef();
61 }
62 break;
63 }
64
65 /* save old csr; switch off INX enable & flag; set RN rounding */
66 oldcsr = ieee754_csr;
67 ieee754_csr.mx &= ~IEEE754_INEXACT;
68 ieee754_csr.sx &= ~IEEE754_INEXACT;
69 ieee754_csr.rm = FPU_CSR_RN;
70
71 /* adjust exponent to prevent overflow */
72 scalx = 0;
73 if (xe > 512) { /* x > 2**-512? */
74 xe -= 512; /* x = x / 2**512 */
75 scalx += 256;
76 } else if (xe < -512) { /* x < 2**-512? */
77 xe += 512; /* x = x * 2**512 */
78 scalx -= 256;
79 }
80
81 x = builddp(0, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT);
82 y = x;
83
84 /* magic initial approximation to almost 8 sig. bits */
85 yh = y.bits >> 32;
86 yh = (yh >> 1) + 0x1ff80000;
87 yh = yh - table[(yh >> 15) & 31];
88 y.bits = ((u64) yh << 32) | (y.bits & 0xffffffff);
89
90 /* Heron's rule once with correction to improve to ~18 sig. bits */
91 /* t=x/y; y=y+t; py[n0]=py[n0]-0x00100006; py[n1]=0; */
92 t = ieee754dp_div(x, y);
93 y = ieee754dp_add(y, t);
94 y.bits -= 0x0010000600000000LL;
95 y.bits &= 0xffffffff00000000LL;
96
97 /* triple to almost 56 sig. bits: y ~= sqrt(x) to within 1 ulp */
98 /* t=y*y; z=t; pt[n0]+=0x00100000; t+=z; z=(x-z)*y; */
99 t = ieee754dp_mul(y, y);
100 z = t;
101 t.bexp += 0x001;
102 t = ieee754dp_add(t, z);
103 z = ieee754dp_mul(ieee754dp_sub(x, z), y);
104
105 /* t=z/(t+x) ; pt[n0]+=0x00100000; y+=t; */
106 t = ieee754dp_div(z, ieee754dp_add(t, x));
107 t.bexp += 0x001;
108 y = ieee754dp_add(y, t);
109
110 /* twiddle last bit to force y correctly rounded */
111
112 /* set RZ, clear INEX flag */
113 ieee754_csr.rm = FPU_CSR_RZ;
114 ieee754_csr.sx &= ~IEEE754_INEXACT;
115
116 /* t=x/y; ...chopped quotient, possibly inexact */
117 t = ieee754dp_div(x, y);
118
119 if (ieee754_csr.sx & IEEE754_INEXACT || t.bits != y.bits) {
120
121 if (!(ieee754_csr.sx & IEEE754_INEXACT))
122 /* t = t-ulp */
123 t.bits -= 1;
124
125 /* add inexact to result status */
126 oldcsr.cx |= IEEE754_INEXACT;
127 oldcsr.sx |= IEEE754_INEXACT;
128
129 switch (oldcsr.rm) {
130 case FPU_CSR_RU:
131 y.bits += 1;
132 fallthrough;
133 case FPU_CSR_RN:
134 t.bits += 1;
135 break;
136 }
137
138 /* y=y+t; ...chopped sum */
139 y = ieee754dp_add(y, t);
140
141 /* adjust scalx for correctly rounded sqrt(x) */
142 scalx -= 1;
143 }
144
145 /* py[n0]=py[n0]+scalx; ...scale back y */
146 y.bexp += scalx;
147
148 /* restore rounding mode, possibly set inexact */
149 ieee754_csr = oldcsr;
150
151 return y;
152}
diff --git a/arch/mips/math-emu/dp_sub.c b/arch/mips/math-emu/dp_sub.c
new file mode 100644
index 000000000..08474ad2a
--- /dev/null
+++ b/arch/mips/math-emu/dp_sub.c
@@ -0,0 +1,172 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/* IEEE754 floating point arithmetic
3 * double precision: common utilities
4 */
5/*
6 * MIPS floating point support
7 * Copyright (C) 1994-2000 Algorithmics Ltd.
8 */
9
10#include "ieee754dp.h"
11
12union ieee754dp ieee754dp_sub(union ieee754dp x, union ieee754dp y)
13{
14 int s;
15
16 COMPXDP;
17 COMPYDP;
18
19 EXPLODEXDP;
20 EXPLODEYDP;
21
22 ieee754_clearcx();
23
24 FLUSHXDP;
25 FLUSHYDP;
26
27 switch (CLPAIR(xc, yc)) {
28 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
29 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
30 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
31 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
32 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
33 return ieee754dp_nanxcpt(y);
34
35 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
36 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
37 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
38 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
39 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
40 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
41 return ieee754dp_nanxcpt(x);
42
43 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
44 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
45 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
46 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
47 return y;
48
49 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
50 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
51 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
52 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
53 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
54 return x;
55
56
57 /*
58 * Infinity handling
59 */
60 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
61 if (xs != ys)
62 return x;
63 ieee754_setcx(IEEE754_INVALID_OPERATION);
64 return ieee754dp_indef();
65
66 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
67 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
68 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
69 return ieee754dp_inf(ys ^ 1);
70
71 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
72 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
73 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
74 return x;
75
76 /*
77 * Zero handling
78 */
79 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
80 if (xs != ys)
81 return x;
82 else
83 return ieee754dp_zero(ieee754_csr.rm == FPU_CSR_RD);
84
85 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
86 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
87 return x;
88
89 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
90 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
91 /* quick fix up */
92 DPSIGN(y) ^= 1;
93 return y;
94
95 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
96 DPDNORMX;
97 fallthrough;
98 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
99 /* normalize ym,ye */
100 DPDNORMY;
101 break;
102
103 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
104 /* normalize xm,xe */
105 DPDNORMX;
106 break;
107
108 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM):
109 break;
110 }
111 /* flip sign of y and handle as add */
112 ys ^= 1;
113
114 assert(xm & DP_HIDDEN_BIT);
115 assert(ym & DP_HIDDEN_BIT);
116
117
118 /* provide guard,round and stick bit dpace */
119 xm <<= 3;
120 ym <<= 3;
121
122 if (xe > ye) {
123 /*
124 * Have to shift y fraction right to align
125 */
126 s = xe - ye;
127 ym = XDPSRS(ym, s);
128 ye += s;
129 } else if (ye > xe) {
130 /*
131 * Have to shift x fraction right to align
132 */
133 s = ye - xe;
134 xm = XDPSRS(xm, s);
135 xe += s;
136 }
137 assert(xe == ye);
138 assert(xe <= DP_EMAX);
139
140 if (xs == ys) {
141 /* generate 28 bit result of adding two 27 bit numbers
142 */
143 xm = xm + ym;
144
145 if (xm >> (DP_FBITS + 1 + 3)) { /* carry out */
146 xm = XDPSRS1(xm); /* shift preserving sticky */
147 xe++;
148 }
149 } else {
150 if (xm >= ym) {
151 xm = xm - ym;
152 } else {
153 xm = ym - xm;
154 xs = ys;
155 }
156 if (xm == 0) {
157 if (ieee754_csr.rm == FPU_CSR_RD)
158 return ieee754dp_zero(1); /* round negative inf. => sign = -1 */
159 else
160 return ieee754dp_zero(0); /* other round modes => sign = 1 */
161 }
162
163 /* normalize to rounding precision
164 */
165 while ((xm >> (DP_FBITS + 3)) == 0) {
166 xm <<= 1;
167 xe--;
168 }
169 }
170
171 return ieee754dp_format(xs, xe, xm);
172}
diff --git a/arch/mips/math-emu/dp_tint.c b/arch/mips/math-emu/dp_tint.c
new file mode 100644
index 000000000..0e6ad35e7
--- /dev/null
+++ b/arch/mips/math-emu/dp_tint.c
@@ -0,0 +1,96 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/* IEEE754 floating point arithmetic
3 * double precision: common utilities
4 */
5/*
6 * MIPS floating point support
7 * Copyright (C) 1994-2000 Algorithmics Ltd.
8 */
9
10#include "ieee754dp.h"
11
12int ieee754dp_tint(union ieee754dp x)
13{
14 u64 residue;
15 int round;
16 int sticky;
17 int odd;
18
19 COMPXDP;
20
21 ieee754_clearcx();
22
23 EXPLODEXDP;
24 FLUSHXDP;
25
26 switch (xc) {
27 case IEEE754_CLASS_SNAN:
28 case IEEE754_CLASS_QNAN:
29 ieee754_setcx(IEEE754_INVALID_OPERATION);
30 return ieee754si_indef();
31
32 case IEEE754_CLASS_INF:
33 ieee754_setcx(IEEE754_INVALID_OPERATION);
34 return ieee754si_overflow(xs);
35
36 case IEEE754_CLASS_ZERO:
37 return 0;
38
39 case IEEE754_CLASS_DNORM:
40 case IEEE754_CLASS_NORM:
41 break;
42 }
43 if (xe > 31) {
44 /* Set invalid. We will only use overflow for floating
45 point overflow */
46 ieee754_setcx(IEEE754_INVALID_OPERATION);
47 return ieee754si_overflow(xs);
48 }
49 /* oh gawd */
50 if (xe > DP_FBITS) {
51 xm <<= xe - DP_FBITS;
52 } else if (xe < DP_FBITS) {
53 if (xe < -1) {
54 residue = xm;
55 round = 0;
56 sticky = residue != 0;
57 xm = 0;
58 } else {
59 residue = xm << (64 - DP_FBITS + xe);
60 round = (residue >> 63) != 0;
61 sticky = (residue << 1) != 0;
62 xm >>= DP_FBITS - xe;
63 }
64 /* Note: At this point upper 32 bits of xm are guaranteed
65 to be zero */
66 odd = (xm & 0x1) != 0x0;
67 switch (ieee754_csr.rm) {
68 case FPU_CSR_RN:
69 if (round && (sticky || odd))
70 xm++;
71 break;
72 case FPU_CSR_RZ:
73 break;
74 case FPU_CSR_RU: /* toward +Infinity */
75 if ((round || sticky) && !xs)
76 xm++;
77 break;
78 case FPU_CSR_RD: /* toward -Infinity */
79 if ((round || sticky) && xs)
80 xm++;
81 break;
82 }
83 /* look for valid corner case 0x80000000 */
84 if ((xm >> 31) != 0 && (xs == 0 || xm != 0x80000000)) {
85 /* This can happen after rounding */
86 ieee754_setcx(IEEE754_INVALID_OPERATION);
87 return ieee754si_overflow(xs);
88 }
89 if (round || sticky)
90 ieee754_setcx(IEEE754_INEXACT);
91 }
92 if (xs)
93 return -xm;
94 else
95 return xm;
96}
diff --git a/arch/mips/math-emu/dp_tlong.c b/arch/mips/math-emu/dp_tlong.c
new file mode 100644
index 000000000..c61ef02d4
--- /dev/null
+++ b/arch/mips/math-emu/dp_tlong.c
@@ -0,0 +1,100 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/* IEEE754 floating point arithmetic
3 * double precision: common utilities
4 */
5/*
6 * MIPS floating point support
7 * Copyright (C) 1994-2000 Algorithmics Ltd.
8 */
9
10#include "ieee754dp.h"
11
12s64 ieee754dp_tlong(union ieee754dp x)
13{
14 u64 residue;
15 int round;
16 int sticky;
17 int odd;
18
19 COMPXDP;
20
21 ieee754_clearcx();
22
23 EXPLODEXDP;
24 FLUSHXDP;
25
26 switch (xc) {
27 case IEEE754_CLASS_SNAN:
28 case IEEE754_CLASS_QNAN:
29 ieee754_setcx(IEEE754_INVALID_OPERATION);
30 return ieee754di_indef();
31
32 case IEEE754_CLASS_INF:
33 ieee754_setcx(IEEE754_INVALID_OPERATION);
34 return ieee754di_overflow(xs);
35
36 case IEEE754_CLASS_ZERO:
37 return 0;
38
39 case IEEE754_CLASS_DNORM:
40 case IEEE754_CLASS_NORM:
41 break;
42 }
43 if (xe >= 63) {
44 /* look for valid corner case */
45 if (xe == 63 && xs && xm == DP_HIDDEN_BIT)
46 return -0x8000000000000000LL;
47 /* Set invalid. We will only use overflow for floating
48 point overflow */
49 ieee754_setcx(IEEE754_INVALID_OPERATION);
50 return ieee754di_overflow(xs);
51 }
52 /* oh gawd */
53 if (xe > DP_FBITS) {
54 xm <<= xe - DP_FBITS;
55 } else if (xe < DP_FBITS) {
56 if (xe < -1) {
57 residue = xm;
58 round = 0;
59 sticky = residue != 0;
60 xm = 0;
61 } else {
62 /* Shifting a u64 64 times does not work,
63 * so we do it in two steps. Be aware that xe
64 * may be -1 */
65 residue = xm << (xe + 1);
66 residue <<= 63 - DP_FBITS;
67 round = (residue >> 63) != 0;
68 sticky = (residue << 1) != 0;
69 xm >>= DP_FBITS - xe;
70 }
71 odd = (xm & 0x1) != 0x0;
72 switch (ieee754_csr.rm) {
73 case FPU_CSR_RN:
74 if (round && (sticky || odd))
75 xm++;
76 break;
77 case FPU_CSR_RZ:
78 break;
79 case FPU_CSR_RU: /* toward +Infinity */
80 if ((round || sticky) && !xs)
81 xm++;
82 break;
83 case FPU_CSR_RD: /* toward -Infinity */
84 if ((round || sticky) && xs)
85 xm++;
86 break;
87 }
88 if ((xm >> 63) != 0) {
89 /* This can happen after rounding */
90 ieee754_setcx(IEEE754_INVALID_OPERATION);
91 return ieee754di_overflow(xs);
92 }
93 if (round || sticky)
94 ieee754_setcx(IEEE754_INEXACT);
95 }
96 if (xs)
97 return -xm;
98 else
99 return xm;
100}
diff --git a/arch/mips/math-emu/dsemul.c b/arch/mips/math-emu/dsemul.c
new file mode 100644
index 000000000..e2d46cb93
--- /dev/null
+++ b/arch/mips/math-emu/dsemul.c
@@ -0,0 +1,308 @@
1// SPDX-License-Identifier: GPL-2.0
2#include <linux/err.h>
3#include <linux/slab.h>
4#include <linux/mm_types.h>
5#include <linux/sched/task.h>
6
7#include <asm/branch.h>
8#include <asm/cacheflush.h>
9#include <asm/fpu_emulator.h>
10#include <asm/inst.h>
11#include <asm/mipsregs.h>
12#include <linux/uaccess.h>
13
14/**
15 * struct emuframe - The 'emulation' frame structure
16 * @emul: The instruction to 'emulate'.
17 * @badinst: A break instruction to cause a return to the kernel.
18 *
19 * This structure defines the frames placed within the delay slot emulation
20 * page in response to a call to mips_dsemul(). Each thread may be allocated
21 * only one frame at any given time. The kernel stores within it the
22 * instruction to be 'emulated' followed by a break instruction, then
23 * executes the frame in user mode. The break causes a trap to the kernel
24 * which leads to do_dsemulret() being called unless the instruction in
25 * @emul causes a trap itself, is a branch, or a signal is delivered to
26 * the thread. In these cases the allocated frame will either be reused by
27 * a subsequent delay slot 'emulation', or be freed during signal delivery or
28 * upon thread exit.
29 *
30 * This approach is used because:
31 *
32 * - Actually emulating all instructions isn't feasible. We would need to
33 * be able to handle instructions from all revisions of the MIPS ISA,
34 * all ASEs & all vendor instruction set extensions. This would be a
35 * whole lot of work & continual maintenance burden as new instructions
36 * are introduced, and in the case of some vendor extensions may not
37 * even be possible. Thus we need to take the approach of actually
38 * executing the instruction.
39 *
40 * - We must execute the instruction within user context. If we were to
41 * execute the instruction in kernel mode then it would have access to
42 * kernel resources without very careful checks, leaving us with a
43 * high potential for security or stability issues to arise.
44 *
45 * - We used to place the frame on the users stack, but this requires
46 * that the stack be executable. This is bad for security so the
47 * per-process page is now used instead.
48 *
49 * - The instruction in @emul may be something entirely invalid for a
50 * delay slot. The user may (intentionally or otherwise) place a branch
51 * in a delay slot, or a kernel mode instruction, or something else
52 * which generates an exception. Thus we can't rely upon the break in
53 * @badinst always being hit. For this reason we track the index of the
54 * frame allocated to each thread, allowing us to clean it up at later
55 * points such as signal delivery or thread exit.
56 *
57 * - The user may generate a fake struct emuframe if they wish, invoking
58 * the BRK_MEMU break instruction themselves. We must therefore not
59 * trust that BRK_MEMU means there's actually a valid frame allocated
60 * to the thread, and must not allow the user to do anything they
61 * couldn't already.
62 */
63struct emuframe {
64 mips_instruction emul;
65 mips_instruction badinst;
66};
67
68static const int emupage_frame_count = PAGE_SIZE / sizeof(struct emuframe);
69
70static inline __user struct emuframe *dsemul_page(void)
71{
72 return (__user struct emuframe *)STACK_TOP;
73}
74
75static int alloc_emuframe(void)
76{
77 mm_context_t *mm_ctx = &current->mm->context;
78 int idx;
79
80retry:
81 spin_lock(&mm_ctx->bd_emupage_lock);
82
83 /* Ensure we have an allocation bitmap */
84 if (!mm_ctx->bd_emupage_allocmap) {
85 mm_ctx->bd_emupage_allocmap =
86 kcalloc(BITS_TO_LONGS(emupage_frame_count),
87 sizeof(unsigned long),
88 GFP_ATOMIC);
89
90 if (!mm_ctx->bd_emupage_allocmap) {
91 idx = BD_EMUFRAME_NONE;
92 goto out_unlock;
93 }
94 }
95
96 /* Attempt to allocate a single bit/frame */
97 idx = bitmap_find_free_region(mm_ctx->bd_emupage_allocmap,
98 emupage_frame_count, 0);
99 if (idx < 0) {
100 /*
101 * Failed to allocate a frame. We'll wait until one becomes
102 * available. We unlock the page so that other threads actually
103 * get the opportunity to free their frames, which means
104 * technically the result of bitmap_full may be incorrect.
105 * However the worst case is that we repeat all this and end up
106 * back here again.
107 */
108 spin_unlock(&mm_ctx->bd_emupage_lock);
109 if (!wait_event_killable(mm_ctx->bd_emupage_queue,
110 !bitmap_full(mm_ctx->bd_emupage_allocmap,
111 emupage_frame_count)))
112 goto retry;
113
114 /* Received a fatal signal - just give in */
115 return BD_EMUFRAME_NONE;
116 }
117
118 /* Success! */
119 pr_debug("allocate emuframe %d to %d\n", idx, current->pid);
120out_unlock:
121 spin_unlock(&mm_ctx->bd_emupage_lock);
122 return idx;
123}
124
125static void free_emuframe(int idx, struct mm_struct *mm)
126{
127 mm_context_t *mm_ctx = &mm->context;
128
129 spin_lock(&mm_ctx->bd_emupage_lock);
130
131 pr_debug("free emuframe %d from %d\n", idx, current->pid);
132 bitmap_clear(mm_ctx->bd_emupage_allocmap, idx, 1);
133
134 /* If some thread is waiting for a frame, now's its chance */
135 wake_up(&mm_ctx->bd_emupage_queue);
136
137 spin_unlock(&mm_ctx->bd_emupage_lock);
138}
139
140static bool within_emuframe(struct pt_regs *regs)
141{
142 unsigned long base = (unsigned long)dsemul_page();
143
144 if (regs->cp0_epc < base)
145 return false;
146 if (regs->cp0_epc >= (base + PAGE_SIZE))
147 return false;
148
149 return true;
150}
151
152bool dsemul_thread_cleanup(struct task_struct *tsk)
153{
154 int fr_idx;
155
156 /* Clear any allocated frame, retrieving its index */
157 fr_idx = atomic_xchg(&tsk->thread.bd_emu_frame, BD_EMUFRAME_NONE);
158
159 /* If no frame was allocated, we're done */
160 if (fr_idx == BD_EMUFRAME_NONE)
161 return false;
162
163 task_lock(tsk);
164
165 /* Free the frame that this thread had allocated */
166 if (tsk->mm)
167 free_emuframe(fr_idx, tsk->mm);
168
169 task_unlock(tsk);
170 return true;
171}
172
173bool dsemul_thread_rollback(struct pt_regs *regs)
174{
175 struct emuframe __user *fr;
176 int fr_idx;
177
178 /* Do nothing if we're not executing from a frame */
179 if (!within_emuframe(regs))
180 return false;
181
182 /* Find the frame being executed */
183 fr_idx = atomic_read(&current->thread.bd_emu_frame);
184 if (fr_idx == BD_EMUFRAME_NONE)
185 return false;
186 fr = &dsemul_page()[fr_idx];
187
188 /*
189 * If the PC is at the emul instruction, roll back to the branch. If
190 * PC is at the badinst (break) instruction, we've already emulated the
191 * instruction so progress to the continue PC. If it's anything else
192 * then something is amiss & the user has branched into some other area
193 * of the emupage - we'll free the allocated frame anyway.
194 */
195 if (msk_isa16_mode(regs->cp0_epc) == (unsigned long)&fr->emul)
196 regs->cp0_epc = current->thread.bd_emu_branch_pc;
197 else if (msk_isa16_mode(regs->cp0_epc) == (unsigned long)&fr->badinst)
198 regs->cp0_epc = current->thread.bd_emu_cont_pc;
199
200 atomic_set(&current->thread.bd_emu_frame, BD_EMUFRAME_NONE);
201 free_emuframe(fr_idx, current->mm);
202 return true;
203}
204
205void dsemul_mm_cleanup(struct mm_struct *mm)
206{
207 mm_context_t *mm_ctx = &mm->context;
208
209 kfree(mm_ctx->bd_emupage_allocmap);
210}
211
212int mips_dsemul(struct pt_regs *regs, mips_instruction ir,
213 unsigned long branch_pc, unsigned long cont_pc)
214{
215 int isa16 = get_isa16_mode(regs->cp0_epc);
216 mips_instruction break_math;
217 unsigned long fr_uaddr;
218 struct emuframe fr;
219 int fr_idx, ret;
220
221 /* NOP is easy */
222 if (ir == 0)
223 return -1;
224
225 /* microMIPS instructions */
226 if (isa16) {
227 union mips_instruction insn = { .word = ir };
228
229 /* NOP16 aka MOVE16 $0, $0 */
230 if ((ir >> 16) == MM_NOP16)
231 return -1;
232
233 /* ADDIUPC */
234 if (insn.mm_a_format.opcode == mm_addiupc_op) {
235 unsigned int rs;
236 s32 v;
237
238 rs = (((insn.mm_a_format.rs + 0xe) & 0xf) + 2);
239 v = regs->cp0_epc & ~3;
240 v += insn.mm_a_format.simmediate << 2;
241 regs->regs[rs] = (long)v;
242 return -1;
243 }
244 }
245
246 pr_debug("dsemul 0x%08lx cont at 0x%08lx\n", regs->cp0_epc, cont_pc);
247
248 /* Allocate a frame if we don't already have one */
249 fr_idx = atomic_read(&current->thread.bd_emu_frame);
250 if (fr_idx == BD_EMUFRAME_NONE)
251 fr_idx = alloc_emuframe();
252 if (fr_idx == BD_EMUFRAME_NONE)
253 return SIGBUS;
254
255 /* Retrieve the appropriately encoded break instruction */
256 break_math = BREAK_MATH(isa16);
257
258 /* Write the instructions to the frame */
259 if (isa16) {
260 union mips_instruction _emul = {
261 .halfword = { ir >> 16, ir }
262 };
263 union mips_instruction _badinst = {
264 .halfword = { break_math >> 16, break_math }
265 };
266
267 fr.emul = _emul.word;
268 fr.badinst = _badinst.word;
269 } else {
270 fr.emul = ir;
271 fr.badinst = break_math;
272 }
273
274 /* Write the frame to user memory */
275 fr_uaddr = (unsigned long)&dsemul_page()[fr_idx];
276 ret = access_process_vm(current, fr_uaddr, &fr, sizeof(fr),
277 FOLL_FORCE | FOLL_WRITE);
278 if (unlikely(ret != sizeof(fr))) {
279 MIPS_FPU_EMU_INC_STATS(errors);
280 free_emuframe(fr_idx, current->mm);
281 return SIGBUS;
282 }
283
284 /* Record the PC of the branch, PC to continue from & frame index */
285 current->thread.bd_emu_branch_pc = branch_pc;
286 current->thread.bd_emu_cont_pc = cont_pc;
287 atomic_set(&current->thread.bd_emu_frame, fr_idx);
288
289 /* Change user register context to execute the frame */
290 regs->cp0_epc = fr_uaddr | isa16;
291
292 return 0;
293}
294
295bool do_dsemulret(struct pt_regs *xcp)
296{
297 /* Cleanup the allocated frame, returning if there wasn't one */
298 if (!dsemul_thread_cleanup(current)) {
299 MIPS_FPU_EMU_INC_STATS(errors);
300 return false;
301 }
302
303 /* Set EPC to return to post-branch instruction */
304 xcp->cp0_epc = current->thread.bd_emu_cont_pc;
305 pr_debug("dsemulret to 0x%08lx\n", xcp->cp0_epc);
306 MIPS_FPU_EMU_INC_STATS(ds_emul);
307 return true;
308}
diff --git a/arch/mips/math-emu/ieee754.c b/arch/mips/math-emu/ieee754.c
new file mode 100644
index 000000000..0ba5dfbd4
--- /dev/null
+++ b/arch/mips/math-emu/ieee754.c
@@ -0,0 +1,83 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/* ieee754 floating point arithmetic
3 * single and double precision
4 *
5 * BUGS
6 * not much dp done
7 * doesn't generate IEEE754_INEXACT
8 */
9/*
10 * MIPS floating point support
11 * Copyright (C) 1994-2000 Algorithmics Ltd.
12 */
13
14#include <linux/compiler.h>
15
16#include "ieee754.h"
17#include "ieee754sp.h"
18#include "ieee754dp.h"
19
20/*
21 * Special constants
22 */
23
24/*
25 * Older GCC requires the inner braces for initialization of union ieee754dp's
26 * anonymous struct member. Without an error will result.
27 */
28#define xPCNST(s, b, m, ebias) \
29{ \
30 { \
31 .sign = (s), \
32 .bexp = (b) + ebias, \
33 .mant = (m) \
34 } \
35}
36
37#define DPCNST(s, b, m) \
38 xPCNST(s, b, m, DP_EBIAS)
39
40const union ieee754dp __ieee754dp_spcvals[] = {
41 DPCNST(0, DP_EMIN - 1, 0x0000000000000ULL), /* + zero */
42 DPCNST(1, DP_EMIN - 1, 0x0000000000000ULL), /* - zero */
43 DPCNST(0, 0, 0x0000000000000ULL), /* + 1.0 */
44 DPCNST(1, 0, 0x0000000000000ULL), /* - 1.0 */
45 DPCNST(0, 3, 0x4000000000000ULL), /* + 10.0 */
46 DPCNST(1, 3, 0x4000000000000ULL), /* - 10.0 */
47 DPCNST(0, DP_EMAX + 1, 0x0000000000000ULL), /* + infinity */
48 DPCNST(1, DP_EMAX + 1, 0x0000000000000ULL), /* - infinity */
49 DPCNST(0, DP_EMAX + 1, 0x7FFFFFFFFFFFFULL), /* + ind legacy qNaN */
50 DPCNST(0, DP_EMAX + 1, 0x8000000000000ULL), /* + indef 2008 qNaN */
51 DPCNST(0, DP_EMAX, 0xFFFFFFFFFFFFFULL), /* + max */
52 DPCNST(1, DP_EMAX, 0xFFFFFFFFFFFFFULL), /* - max */
53 DPCNST(0, DP_EMIN, 0x0000000000000ULL), /* + min normal */
54 DPCNST(1, DP_EMIN, 0x0000000000000ULL), /* - min normal */
55 DPCNST(0, DP_EMIN - 1, 0x0000000000001ULL), /* + min denormal */
56 DPCNST(1, DP_EMIN - 1, 0x0000000000001ULL), /* - min denormal */
57 DPCNST(0, 31, 0x0000000000000ULL), /* + 1.0e31 */
58 DPCNST(0, 63, 0x0000000000000ULL), /* + 1.0e63 */
59};
60
61#define SPCNST(s, b, m) \
62 xPCNST(s, b, m, SP_EBIAS)
63
64const union ieee754sp __ieee754sp_spcvals[] = {
65 SPCNST(0, SP_EMIN - 1, 0x000000), /* + zero */
66 SPCNST(1, SP_EMIN - 1, 0x000000), /* - zero */
67 SPCNST(0, 0, 0x000000), /* + 1.0 */
68 SPCNST(1, 0, 0x000000), /* - 1.0 */
69 SPCNST(0, 3, 0x200000), /* + 10.0 */
70 SPCNST(1, 3, 0x200000), /* - 10.0 */
71 SPCNST(0, SP_EMAX + 1, 0x000000), /* + infinity */
72 SPCNST(1, SP_EMAX + 1, 0x000000), /* - infinity */
73 SPCNST(0, SP_EMAX + 1, 0x3FFFFF), /* + indef legacy quiet NaN */
74 SPCNST(0, SP_EMAX + 1, 0x400000), /* + indef 2008 quiet NaN */
75 SPCNST(0, SP_EMAX, 0x7FFFFF), /* + max normal */
76 SPCNST(1, SP_EMAX, 0x7FFFFF), /* - max normal */
77 SPCNST(0, SP_EMIN, 0x000000), /* + min normal */
78 SPCNST(1, SP_EMIN, 0x000000), /* - min normal */
79 SPCNST(0, SP_EMIN - 1, 0x000001), /* + min denormal */
80 SPCNST(1, SP_EMIN - 1, 0x000001), /* - min denormal */
81 SPCNST(0, 31, 0x000000), /* + 1.0e31 */
82 SPCNST(0, 63, 0x000000), /* + 1.0e63 */
83};
diff --git a/arch/mips/math-emu/ieee754.h b/arch/mips/math-emu/ieee754.h
new file mode 100644
index 000000000..090caa740
--- /dev/null
+++ b/arch/mips/math-emu/ieee754.h
@@ -0,0 +1,311 @@
1/* SPDX-License-Identifier: GPL-2.0-only */
2/*
3 * MIPS floating point support
4 * Copyright (C) 1994-2000 Algorithmics Ltd.
5 *
6 * Nov 7, 2000
7 * Modification to allow integration with Linux kernel
8 *
9 * Kevin D. Kissell, kevink@mips.com and Carsten Langgard, carstenl@mips.com
10 * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
11 */
12#ifndef __ARCH_MIPS_MATH_EMU_IEEE754_H
13#define __ARCH_MIPS_MATH_EMU_IEEE754_H
14
15#include <linux/compiler.h>
16#include <asm/byteorder.h>
17#include <linux/kernel.h>
18#include <linux/types.h>
19#include <linux/sched.h>
20#include <asm/bitfield.h>
21
22union ieee754dp {
23 struct {
24 __BITFIELD_FIELD(unsigned int sign:1,
25 __BITFIELD_FIELD(unsigned int bexp:11,
26 __BITFIELD_FIELD(u64 mant:52,
27 ;)))
28 };
29 u64 bits;
30};
31
32union ieee754sp {
33 struct {
34 __BITFIELD_FIELD(unsigned sign:1,
35 __BITFIELD_FIELD(unsigned bexp:8,
36 __BITFIELD_FIELD(unsigned mant:23,
37 ;)))
38 };
39 u32 bits;
40};
41
42/*
43 * single precision (often aka float)
44*/
45int ieee754sp_class(union ieee754sp x);
46
47union ieee754sp ieee754sp_abs(union ieee754sp x);
48union ieee754sp ieee754sp_neg(union ieee754sp x);
49
50union ieee754sp ieee754sp_add(union ieee754sp x, union ieee754sp y);
51union ieee754sp ieee754sp_sub(union ieee754sp x, union ieee754sp y);
52union ieee754sp ieee754sp_mul(union ieee754sp x, union ieee754sp y);
53union ieee754sp ieee754sp_div(union ieee754sp x, union ieee754sp y);
54
55union ieee754sp ieee754sp_fint(int x);
56union ieee754sp ieee754sp_flong(s64 x);
57union ieee754sp ieee754sp_fdp(union ieee754dp x);
58union ieee754sp ieee754sp_rint(union ieee754sp x);
59
60int ieee754sp_tint(union ieee754sp x);
61s64 ieee754sp_tlong(union ieee754sp x);
62
63int ieee754sp_cmp(union ieee754sp x, union ieee754sp y, int cop, int sig);
64
65union ieee754sp ieee754sp_sqrt(union ieee754sp x);
66
67union ieee754sp ieee754sp_maddf(union ieee754sp z, union ieee754sp x,
68 union ieee754sp y);
69union ieee754sp ieee754sp_msubf(union ieee754sp z, union ieee754sp x,
70 union ieee754sp y);
71union ieee754sp ieee754sp_madd(union ieee754sp z, union ieee754sp x,
72 union ieee754sp y);
73union ieee754sp ieee754sp_msub(union ieee754sp z, union ieee754sp x,
74 union ieee754sp y);
75union ieee754sp ieee754sp_nmadd(union ieee754sp z, union ieee754sp x,
76 union ieee754sp y);
77union ieee754sp ieee754sp_nmsub(union ieee754sp z, union ieee754sp x,
78 union ieee754sp y);
79int ieee754sp_2008class(union ieee754sp x);
80union ieee754sp ieee754sp_fmin(union ieee754sp x, union ieee754sp y);
81union ieee754sp ieee754sp_fmina(union ieee754sp x, union ieee754sp y);
82union ieee754sp ieee754sp_fmax(union ieee754sp x, union ieee754sp y);
83union ieee754sp ieee754sp_fmaxa(union ieee754sp x, union ieee754sp y);
84
85/*
86 * double precision (often aka double)
87*/
88int ieee754dp_class(union ieee754dp x);
89
90union ieee754dp ieee754dp_add(union ieee754dp x, union ieee754dp y);
91union ieee754dp ieee754dp_sub(union ieee754dp x, union ieee754dp y);
92union ieee754dp ieee754dp_mul(union ieee754dp x, union ieee754dp y);
93union ieee754dp ieee754dp_div(union ieee754dp x, union ieee754dp y);
94
95union ieee754dp ieee754dp_abs(union ieee754dp x);
96union ieee754dp ieee754dp_neg(union ieee754dp x);
97
98union ieee754dp ieee754dp_fint(int x);
99union ieee754dp ieee754dp_flong(s64 x);
100union ieee754dp ieee754dp_fsp(union ieee754sp x);
101union ieee754dp ieee754dp_rint(union ieee754dp x);
102
103int ieee754dp_tint(union ieee754dp x);
104s64 ieee754dp_tlong(union ieee754dp x);
105
106int ieee754dp_cmp(union ieee754dp x, union ieee754dp y, int cop, int sig);
107
108union ieee754dp ieee754dp_sqrt(union ieee754dp x);
109
110union ieee754dp ieee754dp_maddf(union ieee754dp z, union ieee754dp x,
111 union ieee754dp y);
112union ieee754dp ieee754dp_msubf(union ieee754dp z, union ieee754dp x,
113 union ieee754dp y);
114union ieee754dp ieee754dp_madd(union ieee754dp z, union ieee754dp x,
115 union ieee754dp y);
116union ieee754dp ieee754dp_msub(union ieee754dp z, union ieee754dp x,
117 union ieee754dp y);
118union ieee754dp ieee754dp_nmadd(union ieee754dp z, union ieee754dp x,
119 union ieee754dp y);
120union ieee754dp ieee754dp_nmsub(union ieee754dp z, union ieee754dp x,
121 union ieee754dp y);
122int ieee754dp_2008class(union ieee754dp x);
123union ieee754dp ieee754dp_fmin(union ieee754dp x, union ieee754dp y);
124union ieee754dp ieee754dp_fmina(union ieee754dp x, union ieee754dp y);
125union ieee754dp ieee754dp_fmax(union ieee754dp x, union ieee754dp y);
126union ieee754dp ieee754dp_fmaxa(union ieee754dp x, union ieee754dp y);
127
128
129/* 5 types of floating point number
130*/
131enum {
132 IEEE754_CLASS_NORM = 0x00,
133 IEEE754_CLASS_ZERO = 0x01,
134 IEEE754_CLASS_DNORM = 0x02,
135 IEEE754_CLASS_INF = 0x03,
136 IEEE754_CLASS_SNAN = 0x04,
137 IEEE754_CLASS_QNAN = 0x05,
138};
139
140/* exception numbers */
141#define IEEE754_INEXACT 0x01
142#define IEEE754_UNDERFLOW 0x02
143#define IEEE754_OVERFLOW 0x04
144#define IEEE754_ZERO_DIVIDE 0x08
145#define IEEE754_INVALID_OPERATION 0x10
146
147/* cmp operators
148*/
149#define IEEE754_CLT 0x01
150#define IEEE754_CEQ 0x02
151#define IEEE754_CGT 0x04
152#define IEEE754_CUN 0x08
153
154/*
155 * The control status register
156 */
157struct _ieee754_csr {
158 __BITFIELD_FIELD(unsigned fcc:7, /* condition[7:1] */
159 __BITFIELD_FIELD(unsigned nod:1, /* set 1 for no denormals */
160 __BITFIELD_FIELD(unsigned c:1, /* condition[0] */
161 __BITFIELD_FIELD(unsigned pad0:3,
162 __BITFIELD_FIELD(unsigned abs2008:1, /* IEEE 754-2008 ABS/NEG.fmt */
163 __BITFIELD_FIELD(unsigned nan2008:1, /* IEEE 754-2008 NaN mode */
164 __BITFIELD_FIELD(unsigned cx:6, /* exceptions this operation */
165 __BITFIELD_FIELD(unsigned mx:5, /* exception enable mask */
166 __BITFIELD_FIELD(unsigned sx:5, /* exceptions total */
167 __BITFIELD_FIELD(unsigned rm:2, /* current rounding mode */
168 ;))))))))))
169};
170#define ieee754_csr (*(struct _ieee754_csr *)(&current->thread.fpu.fcr31))
171
172static inline unsigned int ieee754_getrm(void)
173{
174 return (ieee754_csr.rm);
175}
176
177static inline unsigned int ieee754_setrm(unsigned int rm)
178{
179 return (ieee754_csr.rm = rm);
180}
181
182/*
183 * get current exceptions
184 */
185static inline unsigned int ieee754_getcx(void)
186{
187 return (ieee754_csr.cx);
188}
189
190/* test for current exception condition
191 */
192static inline int ieee754_cxtest(unsigned int n)
193{
194 return (ieee754_csr.cx & n);
195}
196
197/*
198 * get sticky exceptions
199 */
200static inline unsigned int ieee754_getsx(void)
201{
202 return (ieee754_csr.sx);
203}
204
205/* clear sticky conditions
206*/
207static inline unsigned int ieee754_clrsx(void)
208{
209 return (ieee754_csr.sx = 0);
210}
211
212/* test for sticky exception condition
213 */
214static inline int ieee754_sxtest(unsigned int n)
215{
216 return (ieee754_csr.sx & n);
217}
218
219/* debugging */
220union ieee754sp ieee754sp_dump(char *s, union ieee754sp x);
221union ieee754dp ieee754dp_dump(char *s, union ieee754dp x);
222
223#define IEEE754_SPCVAL_PZERO 0 /* +0.0 */
224#define IEEE754_SPCVAL_NZERO 1 /* -0.0 */
225#define IEEE754_SPCVAL_PONE 2 /* +1.0 */
226#define IEEE754_SPCVAL_NONE 3 /* -1.0 */
227#define IEEE754_SPCVAL_PTEN 4 /* +10.0 */
228#define IEEE754_SPCVAL_NTEN 5 /* -10.0 */
229#define IEEE754_SPCVAL_PINFINITY 6 /* +inf */
230#define IEEE754_SPCVAL_NINFINITY 7 /* -inf */
231#define IEEE754_SPCVAL_INDEF_LEG 8 /* legacy quiet NaN */
232#define IEEE754_SPCVAL_INDEF_2008 9 /* IEEE 754-2008 quiet NaN */
233#define IEEE754_SPCVAL_PMAX 10 /* +max norm */
234#define IEEE754_SPCVAL_NMAX 11 /* -max norm */
235#define IEEE754_SPCVAL_PMIN 12 /* +min norm */
236#define IEEE754_SPCVAL_NMIN 13 /* -min norm */
237#define IEEE754_SPCVAL_PMIND 14 /* +min denorm */
238#define IEEE754_SPCVAL_NMIND 15 /* -min denorm */
239#define IEEE754_SPCVAL_P1E31 16 /* + 1.0e31 */
240#define IEEE754_SPCVAL_P1E63 17 /* + 1.0e63 */
241
242extern const union ieee754dp __ieee754dp_spcvals[];
243extern const union ieee754sp __ieee754sp_spcvals[];
244#define ieee754dp_spcvals ((const union ieee754dp *)__ieee754dp_spcvals)
245#define ieee754sp_spcvals ((const union ieee754sp *)__ieee754sp_spcvals)
246
247/*
248 * Return infinity with given sign
249 */
250#define ieee754dp_inf(sn) (ieee754dp_spcvals[IEEE754_SPCVAL_PINFINITY+(sn)])
251#define ieee754dp_zero(sn) (ieee754dp_spcvals[IEEE754_SPCVAL_PZERO+(sn)])
252#define ieee754dp_one(sn) (ieee754dp_spcvals[IEEE754_SPCVAL_PONE+(sn)])
253#define ieee754dp_ten(sn) (ieee754dp_spcvals[IEEE754_SPCVAL_PTEN+(sn)])
254#define ieee754dp_indef() (ieee754dp_spcvals[IEEE754_SPCVAL_INDEF_LEG + \
255 ieee754_csr.nan2008])
256#define ieee754dp_max(sn) (ieee754dp_spcvals[IEEE754_SPCVAL_PMAX+(sn)])
257#define ieee754dp_min(sn) (ieee754dp_spcvals[IEEE754_SPCVAL_PMIN+(sn)])
258#define ieee754dp_mind(sn) (ieee754dp_spcvals[IEEE754_SPCVAL_PMIND+(sn)])
259#define ieee754dp_1e31() (ieee754dp_spcvals[IEEE754_SPCVAL_P1E31])
260#define ieee754dp_1e63() (ieee754dp_spcvals[IEEE754_SPCVAL_P1E63])
261
262#define ieee754sp_inf(sn) (ieee754sp_spcvals[IEEE754_SPCVAL_PINFINITY+(sn)])
263#define ieee754sp_zero(sn) (ieee754sp_spcvals[IEEE754_SPCVAL_PZERO+(sn)])
264#define ieee754sp_one(sn) (ieee754sp_spcvals[IEEE754_SPCVAL_PONE+(sn)])
265#define ieee754sp_ten(sn) (ieee754sp_spcvals[IEEE754_SPCVAL_PTEN+(sn)])
266#define ieee754sp_indef() (ieee754sp_spcvals[IEEE754_SPCVAL_INDEF_LEG + \
267 ieee754_csr.nan2008])
268#define ieee754sp_max(sn) (ieee754sp_spcvals[IEEE754_SPCVAL_PMAX+(sn)])
269#define ieee754sp_min(sn) (ieee754sp_spcvals[IEEE754_SPCVAL_PMIN+(sn)])
270#define ieee754sp_mind(sn) (ieee754sp_spcvals[IEEE754_SPCVAL_PMIND+(sn)])
271#define ieee754sp_1e31() (ieee754sp_spcvals[IEEE754_SPCVAL_P1E31])
272#define ieee754sp_1e63() (ieee754sp_spcvals[IEEE754_SPCVAL_P1E63])
273
274/*
275 * Indefinite integer value
276 */
277static inline int ieee754si_indef(void)
278{
279 return ieee754_csr.nan2008 ? 0 : INT_MAX;
280}
281
282static inline s64 ieee754di_indef(void)
283{
284 return ieee754_csr.nan2008 ? 0 : S64_MAX;
285}
286
287/*
288 * Overflow integer value
289 */
290static inline int ieee754si_overflow(int xs)
291{
292 return ieee754_csr.nan2008 && xs ? INT_MIN : INT_MAX;
293}
294
295static inline s64 ieee754di_overflow(int xs)
296{
297 return ieee754_csr.nan2008 && xs ? S64_MIN : S64_MAX;
298}
299
300/* result types for xctx.rt */
301#define IEEE754_RT_SP 0
302#define IEEE754_RT_DP 1
303#define IEEE754_RT_XP 2
304#define IEEE754_RT_SI 3
305#define IEEE754_RT_DI 4
306
307/* compat */
308#define ieee754dp_fix(x) ieee754dp_tint(x)
309#define ieee754sp_fix(x) ieee754sp_tint(x)
310
311#endif /* __ARCH_MIPS_MATH_EMU_IEEE754_H */
diff --git a/arch/mips/math-emu/ieee754d.c b/arch/mips/math-emu/ieee754d.c
new file mode 100644
index 000000000..586c4db2d
--- /dev/null
+++ b/arch/mips/math-emu/ieee754d.c
@@ -0,0 +1,99 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Some debug functions
4 *
5 * MIPS floating point support
6 *
7 * Copyright (C) 1994-2000 Algorithmics Ltd.
8 *
9 * Nov 7, 2000
10 * Modified to build and operate in Linux kernel environment.
11 *
12 * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
13 * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
14 */
15
16#include <linux/types.h>
17#include <linux/printk.h>
18#include "ieee754.h"
19#include "ieee754sp.h"
20#include "ieee754dp.h"
21
22union ieee754dp ieee754dp_dump(char *m, union ieee754dp x)
23{
24 int i;
25
26 printk("%s", m);
27 printk("<%08x,%08x>\n", (unsigned) (x.bits >> 32),
28 (unsigned) x.bits);
29 printk("\t=");
30 switch (ieee754dp_class(x)) {
31 case IEEE754_CLASS_QNAN:
32 case IEEE754_CLASS_SNAN:
33 printk("Nan %c", DPSIGN(x) ? '-' : '+');
34 for (i = DP_FBITS - 1; i >= 0; i--)
35 printk("%c", DPMANT(x) & DP_MBIT(i) ? '1' : '0');
36 break;
37 case IEEE754_CLASS_INF:
38 printk("%cInfinity", DPSIGN(x) ? '-' : '+');
39 break;
40 case IEEE754_CLASS_ZERO:
41 printk("%cZero", DPSIGN(x) ? '-' : '+');
42 break;
43 case IEEE754_CLASS_DNORM:
44 printk("%c0.", DPSIGN(x) ? '-' : '+');
45 for (i = DP_FBITS - 1; i >= 0; i--)
46 printk("%c", DPMANT(x) & DP_MBIT(i) ? '1' : '0');
47 printk("e%d", DPBEXP(x) - DP_EBIAS);
48 break;
49 case IEEE754_CLASS_NORM:
50 printk("%c1.", DPSIGN(x) ? '-' : '+');
51 for (i = DP_FBITS - 1; i >= 0; i--)
52 printk("%c", DPMANT(x) & DP_MBIT(i) ? '1' : '0');
53 printk("e%d", DPBEXP(x) - DP_EBIAS);
54 break;
55 default:
56 printk("Illegal/Unknown IEEE754 value class");
57 }
58 printk("\n");
59 return x;
60}
61
62union ieee754sp ieee754sp_dump(char *m, union ieee754sp x)
63{
64 int i;
65
66 printk("%s=", m);
67 printk("<%08x>\n", (unsigned) x.bits);
68 printk("\t=");
69 switch (ieee754sp_class(x)) {
70 case IEEE754_CLASS_QNAN:
71 case IEEE754_CLASS_SNAN:
72 printk("Nan %c", SPSIGN(x) ? '-' : '+');
73 for (i = SP_FBITS - 1; i >= 0; i--)
74 printk("%c", SPMANT(x) & SP_MBIT(i) ? '1' : '0');
75 break;
76 case IEEE754_CLASS_INF:
77 printk("%cInfinity", SPSIGN(x) ? '-' : '+');
78 break;
79 case IEEE754_CLASS_ZERO:
80 printk("%cZero", SPSIGN(x) ? '-' : '+');
81 break;
82 case IEEE754_CLASS_DNORM:
83 printk("%c0.", SPSIGN(x) ? '-' : '+');
84 for (i = SP_FBITS - 1; i >= 0; i--)
85 printk("%c", SPMANT(x) & SP_MBIT(i) ? '1' : '0');
86 printk("e%d", SPBEXP(x) - SP_EBIAS);
87 break;
88 case IEEE754_CLASS_NORM:
89 printk("%c1.", SPSIGN(x) ? '-' : '+');
90 for (i = SP_FBITS - 1; i >= 0; i--)
91 printk("%c", SPMANT(x) & SP_MBIT(i) ? '1' : '0');
92 printk("e%d", SPBEXP(x) - SP_EBIAS);
93 break;
94 default:
95 printk("Illegal/Unknown IEEE754 value class");
96 }
97 printk("\n");
98 return x;
99}
diff --git a/arch/mips/math-emu/ieee754dp.c b/arch/mips/math-emu/ieee754dp.c
new file mode 100644
index 000000000..07ef146e2
--- /dev/null
+++ b/arch/mips/math-emu/ieee754dp.c
@@ -0,0 +1,197 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/* IEEE754 floating point arithmetic
3 * double precision: common utilities
4 */
5/*
6 * MIPS floating point support
7 * Copyright (C) 1994-2000 Algorithmics Ltd.
8 */
9
10#include <linux/compiler.h>
11
12#include "ieee754dp.h"
13
14int ieee754dp_class(union ieee754dp x)
15{
16 COMPXDP;
17 EXPLODEXDP;
18 return xc;
19}
20
21static inline int ieee754dp_isnan(union ieee754dp x)
22{
23 return ieee754_class_nan(ieee754dp_class(x));
24}
25
26static inline int ieee754dp_issnan(union ieee754dp x)
27{
28 int qbit;
29
30 assert(ieee754dp_isnan(x));
31 qbit = (DPMANT(x) & DP_MBIT(DP_FBITS - 1)) == DP_MBIT(DP_FBITS - 1);
32 return ieee754_csr.nan2008 ^ qbit;
33}
34
35
36/*
37 * Raise the Invalid Operation IEEE 754 exception
38 * and convert the signaling NaN supplied to a quiet NaN.
39 */
40union ieee754dp __cold ieee754dp_nanxcpt(union ieee754dp r)
41{
42 assert(ieee754dp_issnan(r));
43
44 ieee754_setcx(IEEE754_INVALID_OPERATION);
45 if (ieee754_csr.nan2008) {
46 DPMANT(r) |= DP_MBIT(DP_FBITS - 1);
47 } else {
48 DPMANT(r) &= ~DP_MBIT(DP_FBITS - 1);
49 if (!ieee754dp_isnan(r))
50 DPMANT(r) |= DP_MBIT(DP_FBITS - 2);
51 }
52
53 return r;
54}
55
56static u64 ieee754dp_get_rounding(int sn, u64 xm)
57{
58 /* inexact must round of 3 bits
59 */
60 if (xm & (DP_MBIT(3) - 1)) {
61 switch (ieee754_csr.rm) {
62 case FPU_CSR_RZ:
63 break;
64 case FPU_CSR_RN:
65 xm += 0x3 + ((xm >> 3) & 1);
66 /* xm += (xm&0x8)?0x4:0x3 */
67 break;
68 case FPU_CSR_RU: /* toward +Infinity */
69 if (!sn) /* ?? */
70 xm += 0x8;
71 break;
72 case FPU_CSR_RD: /* toward -Infinity */
73 if (sn) /* ?? */
74 xm += 0x8;
75 break;
76 }
77 }
78 return xm;
79}
80
81
82/* generate a normal/denormal number with over,under handling
83 * sn is sign
84 * xe is an unbiased exponent
85 * xm is 3bit extended precision value.
86 */
87union ieee754dp ieee754dp_format(int sn, int xe, u64 xm)
88{
89 assert(xm); /* we don't gen exact zeros (probably should) */
90
91 assert((xm >> (DP_FBITS + 1 + 3)) == 0); /* no excess */
92 assert(xm & (DP_HIDDEN_BIT << 3));
93
94 if (xe < DP_EMIN) {
95 /* strip lower bits */
96 int es = DP_EMIN - xe;
97
98 if (ieee754_csr.nod) {
99 ieee754_setcx(IEEE754_UNDERFLOW);
100 ieee754_setcx(IEEE754_INEXACT);
101
102 switch(ieee754_csr.rm) {
103 case FPU_CSR_RN:
104 case FPU_CSR_RZ:
105 return ieee754dp_zero(sn);
106 case FPU_CSR_RU: /* toward +Infinity */
107 if (sn == 0)
108 return ieee754dp_min(0);
109 else
110 return ieee754dp_zero(1);
111 case FPU_CSR_RD: /* toward -Infinity */
112 if (sn == 0)
113 return ieee754dp_zero(0);
114 else
115 return ieee754dp_min(1);
116 }
117 }
118
119 if (xe == DP_EMIN - 1 &&
120 ieee754dp_get_rounding(sn, xm) >> (DP_FBITS + 1 + 3))
121 {
122 /* Not tiny after rounding */
123 ieee754_setcx(IEEE754_INEXACT);
124 xm = ieee754dp_get_rounding(sn, xm);
125 xm >>= 1;
126 /* Clear grs bits */
127 xm &= ~(DP_MBIT(3) - 1);
128 xe++;
129 }
130 else {
131 /* sticky right shift es bits
132 */
133 xm = XDPSRS(xm, es);
134 xe += es;
135 assert((xm & (DP_HIDDEN_BIT << 3)) == 0);
136 assert(xe == DP_EMIN);
137 }
138 }
139 if (xm & (DP_MBIT(3) - 1)) {
140 ieee754_setcx(IEEE754_INEXACT);
141 if ((xm & (DP_HIDDEN_BIT << 3)) == 0) {
142 ieee754_setcx(IEEE754_UNDERFLOW);
143 }
144
145 /* inexact must round of 3 bits
146 */
147 xm = ieee754dp_get_rounding(sn, xm);
148 /* adjust exponent for rounding add overflowing
149 */
150 if (xm >> (DP_FBITS + 3 + 1)) {
151 /* add causes mantissa overflow */
152 xm >>= 1;
153 xe++;
154 }
155 }
156 /* strip grs bits */
157 xm >>= 3;
158
159 assert((xm >> (DP_FBITS + 1)) == 0); /* no excess */
160 assert(xe >= DP_EMIN);
161
162 if (xe > DP_EMAX) {
163 ieee754_setcx(IEEE754_OVERFLOW);
164 ieee754_setcx(IEEE754_INEXACT);
165 /* -O can be table indexed by (rm,sn) */
166 switch (ieee754_csr.rm) {
167 case FPU_CSR_RN:
168 return ieee754dp_inf(sn);
169 case FPU_CSR_RZ:
170 return ieee754dp_max(sn);
171 case FPU_CSR_RU: /* toward +Infinity */
172 if (sn == 0)
173 return ieee754dp_inf(0);
174 else
175 return ieee754dp_max(1);
176 case FPU_CSR_RD: /* toward -Infinity */
177 if (sn == 0)
178 return ieee754dp_max(0);
179 else
180 return ieee754dp_inf(1);
181 }
182 }
183 /* gen norm/denorm/zero */
184
185 if ((xm & DP_HIDDEN_BIT) == 0) {
186 /* we underflow (tiny/zero) */
187 assert(xe == DP_EMIN);
188 if (ieee754_csr.mx & IEEE754_UNDERFLOW)
189 ieee754_setcx(IEEE754_UNDERFLOW);
190 return builddp(sn, DP_EMIN - 1 + DP_EBIAS, xm);
191 } else {
192 assert((xm >> (DP_FBITS + 1)) == 0); /* no excess */
193 assert(xm & DP_HIDDEN_BIT);
194
195 return builddp(sn, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT);
196 }
197}
diff --git a/arch/mips/math-emu/ieee754dp.h b/arch/mips/math-emu/ieee754dp.h
new file mode 100644
index 000000000..b7c43a99a
--- /dev/null
+++ b/arch/mips/math-emu/ieee754dp.h
@@ -0,0 +1,73 @@
1/* SPDX-License-Identifier: GPL-2.0-only */
2/*
3 * IEEE754 floating point
4 * double precision internal header file
5 */
6/*
7 * MIPS floating point support
8 * Copyright (C) 1994-2000 Algorithmics Ltd.
9 */
10
11#include <linux/compiler.h>
12
13#include "ieee754int.h"
14
15#define assert(expr) ((void)0)
16
17#define DP_EBIAS 1023
18#define DP_EMIN (-1022)
19#define DP_EMAX 1023
20#define DP_FBITS 52
21#define DP_MBITS 52
22
23#define DP_MBIT(x) ((u64)1 << (x))
24#define DP_HIDDEN_BIT DP_MBIT(DP_FBITS)
25#define DP_SIGN_BIT DP_MBIT(63)
26
27#define DPSIGN(dp) (dp.sign)
28#define DPBEXP(dp) (dp.bexp)
29#define DPMANT(dp) (dp.mant)
30
31static inline int ieee754dp_finite(union ieee754dp x)
32{
33 return DPBEXP(x) != DP_EMAX + 1 + DP_EBIAS;
34}
35
36/* 3bit extended double precision sticky right shift */
37#define XDPSRS(v,rs) \
38 ((rs > (DP_FBITS+3))?1:((v) >> (rs)) | ((v) << (64-(rs)) != 0))
39
40#define XDPSRSX1() \
41 (xe++, (xm = (xm >> 1) | (xm & 1)))
42
43#define XDPSRS1(v) \
44 (((v) >> 1) | ((v) & 1))
45
46/* 32bit * 32bit => 64bit unsigned integer multiplication */
47#define DPXMULT(x, y) ((u64)(x) * (u64)y)
48
49/* convert denormal to normalized with extended exponent */
50#define DPDNORMx(m,e) \
51 while ((m >> DP_FBITS) == 0) { m <<= 1; e--; }
52#define DPDNORMX DPDNORMx(xm, xe)
53#define DPDNORMY DPDNORMx(ym, ye)
54#define DPDNORMZ DPDNORMx(zm, ze)
55
56static inline union ieee754dp builddp(int s, int bx, u64 m)
57{
58 union ieee754dp r;
59
60 assert((s) == 0 || (s) == 1);
61 assert((bx) >= DP_EMIN - 1 + DP_EBIAS
62 && (bx) <= DP_EMAX + 1 + DP_EBIAS);
63 assert(((m) >> DP_FBITS) == 0);
64
65 r.sign = s;
66 r.bexp = bx;
67 r.mant = m;
68
69 return r;
70}
71
72extern union ieee754dp __cold ieee754dp_nanxcpt(union ieee754dp);
73extern union ieee754dp ieee754dp_format(int, int, u64);
diff --git a/arch/mips/math-emu/ieee754int.h b/arch/mips/math-emu/ieee754int.h
new file mode 100644
index 000000000..2c3b13546
--- /dev/null
+++ b/arch/mips/math-emu/ieee754int.h
@@ -0,0 +1,149 @@
1/* SPDX-License-Identifier: GPL-2.0-only */
2/*
3 * IEEE754 floating point
4 * common internal header file
5 */
6/*
7 * MIPS floating point support
8 * Copyright (C) 1994-2000 Algorithmics Ltd.
9 */
10#ifndef __IEEE754INT_H
11#define __IEEE754INT_H
12
13#include "ieee754.h"
14
15#define CLPAIR(x, y) ((x)*6+(y))
16
17enum maddf_flags {
18 MADDF_NEGATE_PRODUCT = 1 << 0,
19 MADDF_NEGATE_ADDITION = 1 << 1,
20};
21
22static inline void ieee754_clearcx(void)
23{
24 ieee754_csr.cx = 0;
25}
26
27static inline void ieee754_setcx(const unsigned int flags)
28{
29 ieee754_csr.cx |= flags;
30 ieee754_csr.sx |= flags;
31}
32
33static inline int ieee754_setandtestcx(const unsigned int x)
34{
35 ieee754_setcx(x);
36
37 return ieee754_csr.mx & x;
38}
39
40static inline int ieee754_class_nan(int xc)
41{
42 return xc >= IEEE754_CLASS_SNAN;
43}
44
45#define COMPXSP \
46 unsigned int xm; int xe; int xs __maybe_unused; int xc
47
48#define COMPYSP \
49 unsigned int ym; int ye; int ys; int yc
50
51#define COMPZSP \
52 unsigned int zm; int ze; int zs; int zc
53
54#define EXPLODESP(v, vc, vs, ve, vm) \
55{ \
56 vs = SPSIGN(v); \
57 ve = SPBEXP(v); \
58 vm = SPMANT(v); \
59 if (ve == SP_EMAX+1+SP_EBIAS) { \
60 if (vm == 0) \
61 vc = IEEE754_CLASS_INF; \
62 else if (ieee754_csr.nan2008 ^ !(vm & SP_MBIT(SP_FBITS - 1))) \
63 vc = IEEE754_CLASS_QNAN; \
64 else \
65 vc = IEEE754_CLASS_SNAN; \
66 } else if (ve == SP_EMIN-1+SP_EBIAS) { \
67 if (vm) { \
68 ve = SP_EMIN; \
69 vc = IEEE754_CLASS_DNORM; \
70 } else \
71 vc = IEEE754_CLASS_ZERO; \
72 } else { \
73 ve -= SP_EBIAS; \
74 vm |= SP_HIDDEN_BIT; \
75 vc = IEEE754_CLASS_NORM; \
76 } \
77}
78#define EXPLODEXSP EXPLODESP(x, xc, xs, xe, xm)
79#define EXPLODEYSP EXPLODESP(y, yc, ys, ye, ym)
80#define EXPLODEZSP EXPLODESP(z, zc, zs, ze, zm)
81
82
83#define COMPXDP \
84 u64 xm; int xe; int xs __maybe_unused; int xc
85
86#define COMPYDP \
87 u64 ym; int ye; int ys; int yc
88
89#define COMPZDP \
90 u64 zm; int ze; int zs; int zc
91
92#define EXPLODEDP(v, vc, vs, ve, vm) \
93{ \
94 vm = DPMANT(v); \
95 vs = DPSIGN(v); \
96 ve = DPBEXP(v); \
97 if (ve == DP_EMAX+1+DP_EBIAS) { \
98 if (vm == 0) \
99 vc = IEEE754_CLASS_INF; \
100 else if (ieee754_csr.nan2008 ^ !(vm & DP_MBIT(DP_FBITS - 1))) \
101 vc = IEEE754_CLASS_QNAN; \
102 else \
103 vc = IEEE754_CLASS_SNAN; \
104 } else if (ve == DP_EMIN-1+DP_EBIAS) { \
105 if (vm) { \
106 ve = DP_EMIN; \
107 vc = IEEE754_CLASS_DNORM; \
108 } else \
109 vc = IEEE754_CLASS_ZERO; \
110 } else { \
111 ve -= DP_EBIAS; \
112 vm |= DP_HIDDEN_BIT; \
113 vc = IEEE754_CLASS_NORM; \
114 } \
115}
116#define EXPLODEXDP EXPLODEDP(x, xc, xs, xe, xm)
117#define EXPLODEYDP EXPLODEDP(y, yc, ys, ye, ym)
118#define EXPLODEZDP EXPLODEDP(z, zc, zs, ze, zm)
119
120#define FLUSHDP(v, vc, vs, ve, vm) \
121 if (vc==IEEE754_CLASS_DNORM) { \
122 if (ieee754_csr.nod) { \
123 ieee754_setcx(IEEE754_INEXACT); \
124 vc = IEEE754_CLASS_ZERO; \
125 ve = DP_EMIN-1+DP_EBIAS; \
126 vm = 0; \
127 v = ieee754dp_zero(vs); \
128 } \
129 }
130
131#define FLUSHSP(v, vc, vs, ve, vm) \
132 if (vc==IEEE754_CLASS_DNORM) { \
133 if (ieee754_csr.nod) { \
134 ieee754_setcx(IEEE754_INEXACT); \
135 vc = IEEE754_CLASS_ZERO; \
136 ve = SP_EMIN-1+SP_EBIAS; \
137 vm = 0; \
138 v = ieee754sp_zero(vs); \
139 } \
140 }
141
142#define FLUSHXDP FLUSHDP(x, xc, xs, xe, xm)
143#define FLUSHYDP FLUSHDP(y, yc, ys, ye, ym)
144#define FLUSHZDP FLUSHDP(z, zc, zs, ze, zm)
145#define FLUSHXSP FLUSHSP(x, xc, xs, xe, xm)
146#define FLUSHYSP FLUSHSP(y, yc, ys, ye, ym)
147#define FLUSHZSP FLUSHSP(z, zc, zs, ze, zm)
148
149#endif /* __IEEE754INT_H */
diff --git a/arch/mips/math-emu/ieee754sp.c b/arch/mips/math-emu/ieee754sp.c
new file mode 100644
index 000000000..0b6267bc8
--- /dev/null
+++ b/arch/mips/math-emu/ieee754sp.c
@@ -0,0 +1,196 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/* IEEE754 floating point arithmetic
3 * single precision
4 */
5/*
6 * MIPS floating point support
7 * Copyright (C) 1994-2000 Algorithmics Ltd.
8 */
9
10#include <linux/compiler.h>
11
12#include "ieee754sp.h"
13
14int ieee754sp_class(union ieee754sp x)
15{
16 COMPXSP;
17 EXPLODEXSP;
18 return xc;
19}
20
21static inline int ieee754sp_isnan(union ieee754sp x)
22{
23 return ieee754_class_nan(ieee754sp_class(x));
24}
25
26static inline int ieee754sp_issnan(union ieee754sp x)
27{
28 int qbit;
29
30 assert(ieee754sp_isnan(x));
31 qbit = (SPMANT(x) & SP_MBIT(SP_FBITS - 1)) == SP_MBIT(SP_FBITS - 1);
32 return ieee754_csr.nan2008 ^ qbit;
33}
34
35
36/*
37 * Raise the Invalid Operation IEEE 754 exception
38 * and convert the signaling NaN supplied to a quiet NaN.
39 */
40union ieee754sp __cold ieee754sp_nanxcpt(union ieee754sp r)
41{
42 assert(ieee754sp_issnan(r));
43
44 ieee754_setcx(IEEE754_INVALID_OPERATION);
45 if (ieee754_csr.nan2008) {
46 SPMANT(r) |= SP_MBIT(SP_FBITS - 1);
47 } else {
48 SPMANT(r) &= ~SP_MBIT(SP_FBITS - 1);
49 if (!ieee754sp_isnan(r))
50 SPMANT(r) |= SP_MBIT(SP_FBITS - 2);
51 }
52
53 return r;
54}
55
56static unsigned int ieee754sp_get_rounding(int sn, unsigned int xm)
57{
58 /* inexact must round of 3 bits
59 */
60 if (xm & (SP_MBIT(3) - 1)) {
61 switch (ieee754_csr.rm) {
62 case FPU_CSR_RZ:
63 break;
64 case FPU_CSR_RN:
65 xm += 0x3 + ((xm >> 3) & 1);
66 /* xm += (xm&0x8)?0x4:0x3 */
67 break;
68 case FPU_CSR_RU: /* toward +Infinity */
69 if (!sn) /* ?? */
70 xm += 0x8;
71 break;
72 case FPU_CSR_RD: /* toward -Infinity */
73 if (sn) /* ?? */
74 xm += 0x8;
75 break;
76 }
77 }
78 return xm;
79}
80
81
82/* generate a normal/denormal number with over,under handling
83 * sn is sign
84 * xe is an unbiased exponent
85 * xm is 3bit extended precision value.
86 */
87union ieee754sp ieee754sp_format(int sn, int xe, unsigned int xm)
88{
89 assert(xm); /* we don't gen exact zeros (probably should) */
90
91 assert((xm >> (SP_FBITS + 1 + 3)) == 0); /* no excess */
92 assert(xm & (SP_HIDDEN_BIT << 3));
93
94 if (xe < SP_EMIN) {
95 /* strip lower bits */
96 int es = SP_EMIN - xe;
97
98 if (ieee754_csr.nod) {
99 ieee754_setcx(IEEE754_UNDERFLOW);
100 ieee754_setcx(IEEE754_INEXACT);
101
102 switch(ieee754_csr.rm) {
103 case FPU_CSR_RN:
104 case FPU_CSR_RZ:
105 return ieee754sp_zero(sn);
106 case FPU_CSR_RU: /* toward +Infinity */
107 if (sn == 0)
108 return ieee754sp_min(0);
109 else
110 return ieee754sp_zero(1);
111 case FPU_CSR_RD: /* toward -Infinity */
112 if (sn == 0)
113 return ieee754sp_zero(0);
114 else
115 return ieee754sp_min(1);
116 }
117 }
118
119 if (xe == SP_EMIN - 1 &&
120 ieee754sp_get_rounding(sn, xm) >> (SP_FBITS + 1 + 3))
121 {
122 /* Not tiny after rounding */
123 ieee754_setcx(IEEE754_INEXACT);
124 xm = ieee754sp_get_rounding(sn, xm);
125 xm >>= 1;
126 /* Clear grs bits */
127 xm &= ~(SP_MBIT(3) - 1);
128 xe++;
129 } else {
130 /* sticky right shift es bits
131 */
132 xm = XSPSRS(xm, es);
133 xe += es;
134 assert((xm & (SP_HIDDEN_BIT << 3)) == 0);
135 assert(xe == SP_EMIN);
136 }
137 }
138 if (xm & (SP_MBIT(3) - 1)) {
139 ieee754_setcx(IEEE754_INEXACT);
140 if ((xm & (SP_HIDDEN_BIT << 3)) == 0) {
141 ieee754_setcx(IEEE754_UNDERFLOW);
142 }
143
144 /* inexact must round of 3 bits
145 */
146 xm = ieee754sp_get_rounding(sn, xm);
147 /* adjust exponent for rounding add overflowing
148 */
149 if (xm >> (SP_FBITS + 1 + 3)) {
150 /* add causes mantissa overflow */
151 xm >>= 1;
152 xe++;
153 }
154 }
155 /* strip grs bits */
156 xm >>= 3;
157
158 assert((xm >> (SP_FBITS + 1)) == 0); /* no excess */
159 assert(xe >= SP_EMIN);
160
161 if (xe > SP_EMAX) {
162 ieee754_setcx(IEEE754_OVERFLOW);
163 ieee754_setcx(IEEE754_INEXACT);
164 /* -O can be table indexed by (rm,sn) */
165 switch (ieee754_csr.rm) {
166 case FPU_CSR_RN:
167 return ieee754sp_inf(sn);
168 case FPU_CSR_RZ:
169 return ieee754sp_max(sn);
170 case FPU_CSR_RU: /* toward +Infinity */
171 if (sn == 0)
172 return ieee754sp_inf(0);
173 else
174 return ieee754sp_max(1);
175 case FPU_CSR_RD: /* toward -Infinity */
176 if (sn == 0)
177 return ieee754sp_max(0);
178 else
179 return ieee754sp_inf(1);
180 }
181 }
182 /* gen norm/denorm/zero */
183
184 if ((xm & SP_HIDDEN_BIT) == 0) {
185 /* we underflow (tiny/zero) */
186 assert(xe == SP_EMIN);
187 if (ieee754_csr.mx & IEEE754_UNDERFLOW)
188 ieee754_setcx(IEEE754_UNDERFLOW);
189 return buildsp(sn, SP_EMIN - 1 + SP_EBIAS, xm);
190 } else {
191 assert((xm >> (SP_FBITS + 1)) == 0); /* no excess */
192 assert(xm & SP_HIDDEN_BIT);
193
194 return buildsp(sn, xe + SP_EBIAS, xm & ~SP_HIDDEN_BIT);
195 }
196}
diff --git a/arch/mips/math-emu/ieee754sp.h b/arch/mips/math-emu/ieee754sp.h
new file mode 100644
index 000000000..79040f890
--- /dev/null
+++ b/arch/mips/math-emu/ieee754sp.h
@@ -0,0 +1,77 @@
1/* SPDX-License-Identifier: GPL-2.0-only */
2/*
3 * IEEE754 floating point
4 * double precision internal header file
5 */
6/*
7 * MIPS floating point support
8 * Copyright (C) 1994-2000 Algorithmics Ltd.
9 */
10
11#include <linux/compiler.h>
12
13#include "ieee754int.h"
14
15#define assert(expr) ((void)0)
16
17#define SP_EBIAS 127
18#define SP_EMIN (-126)
19#define SP_EMAX 127
20#define SP_FBITS 23
21#define SP_MBITS 23
22
23#define SP_MBIT(x) ((u32)1 << (x))
24#define SP_HIDDEN_BIT SP_MBIT(SP_FBITS)
25#define SP_SIGN_BIT SP_MBIT(31)
26
27#define SPSIGN(sp) (sp.sign)
28#define SPBEXP(sp) (sp.bexp)
29#define SPMANT(sp) (sp.mant)
30
31static inline int ieee754sp_finite(union ieee754sp x)
32{
33 return SPBEXP(x) != SP_EMAX + 1 + SP_EBIAS;
34}
35
36/* 64 bit right shift with rounding */
37#define XSPSRS64(v, rs) \
38 (((rs) >= 64) ? ((v) != 0) : ((v) >> (rs)) | ((v) << (64-(rs)) != 0))
39
40/* 3bit extended single precision sticky right shift */
41#define XSPSRS(v, rs) \
42 ((rs > (SP_FBITS+3))?1:((v) >> (rs)) | ((v) << (32-(rs)) != 0))
43
44#define XSPSRS1(m) \
45 ((m >> 1) | (m & 1))
46
47#define SPXSRSX1() \
48 (xe++, (xm = XSPSRS1(xm)))
49
50#define SPXSRSY1() \
51 (ye++, (ym = XSPSRS1(ym)))
52
53/* convert denormal to normalized with extended exponent */
54#define SPDNORMx(m,e) \
55 while ((m >> SP_FBITS) == 0) { m <<= 1; e--; }
56#define SPDNORMX SPDNORMx(xm, xe)
57#define SPDNORMY SPDNORMx(ym, ye)
58#define SPDNORMZ SPDNORMx(zm, ze)
59
60static inline union ieee754sp buildsp(int s, int bx, unsigned int m)
61{
62 union ieee754sp r;
63
64 assert((s) == 0 || (s) == 1);
65 assert((bx) >= SP_EMIN - 1 + SP_EBIAS
66 && (bx) <= SP_EMAX + 1 + SP_EBIAS);
67 assert(((m) >> SP_FBITS) == 0);
68
69 r.sign = s;
70 r.bexp = bx;
71 r.mant = m;
72
73 return r;
74}
75
76extern union ieee754sp __cold ieee754sp_nanxcpt(union ieee754sp);
77extern union ieee754sp ieee754sp_format(int, int, unsigned);
diff --git a/arch/mips/math-emu/me-debugfs.c b/arch/mips/math-emu/me-debugfs.c
new file mode 100644
index 000000000..d5ad76b2b
--- /dev/null
+++ b/arch/mips/math-emu/me-debugfs.c
@@ -0,0 +1,353 @@
1// SPDX-License-Identifier: GPL-2.0
2#include <linux/cpumask.h>
3#include <linux/debugfs.h>
4#include <linux/fs.h>
5#include <linux/init.h>
6#include <linux/percpu.h>
7#include <linux/types.h>
8#include <asm/debug.h>
9#include <asm/fpu_emulator.h>
10#include <asm/local.h>
11
12DEFINE_PER_CPU(struct mips_fpu_emulator_stats, fpuemustats);
13
14static int fpuemu_stat_get(void *data, u64 *val)
15{
16 int cpu;
17 unsigned long sum = 0;
18
19 for_each_online_cpu(cpu) {
20 struct mips_fpu_emulator_stats *ps;
21 local_t *pv;
22
23 ps = &per_cpu(fpuemustats, cpu);
24 pv = (void *)ps + (unsigned long)data;
25 sum += local_read(pv);
26 }
27 *val = sum;
28 return 0;
29}
30DEFINE_SIMPLE_ATTRIBUTE(fops_fpuemu_stat, fpuemu_stat_get, NULL, "%llu\n");
31
32/*
33 * Used to obtain names for a debugfs instruction counter, given field name
34 * in fpuemustats structure. For example, for input "cmp_sueq_d", the output
35 * would be "cmp.sueq.d". This is needed since dots are not allowed to be
36 * used in structure field names, and are, on the other hand, desired to be
37 * used in debugfs item names to be clearly associated to corresponding
38 * MIPS FPU instructions.
39 */
40static void adjust_instruction_counter_name(char *out_name, char *in_name)
41{
42 int i = 0;
43
44 strcpy(out_name, in_name);
45 while (in_name[i] != '\0') {
46 if (out_name[i] == '_')
47 out_name[i] = '.';
48 i++;
49 }
50}
51
52static int fpuemustats_clear_show(struct seq_file *s, void *unused)
53{
54 __this_cpu_write((fpuemustats).emulated, 0);
55 __this_cpu_write((fpuemustats).loads, 0);
56 __this_cpu_write((fpuemustats).stores, 0);
57 __this_cpu_write((fpuemustats).branches, 0);
58 __this_cpu_write((fpuemustats).cp1ops, 0);
59 __this_cpu_write((fpuemustats).cp1xops, 0);
60 __this_cpu_write((fpuemustats).errors, 0);
61 __this_cpu_write((fpuemustats).ieee754_inexact, 0);
62 __this_cpu_write((fpuemustats).ieee754_underflow, 0);
63 __this_cpu_write((fpuemustats).ieee754_overflow, 0);
64 __this_cpu_write((fpuemustats).ieee754_zerodiv, 0);
65 __this_cpu_write((fpuemustats).ieee754_invalidop, 0);
66 __this_cpu_write((fpuemustats).ds_emul, 0);
67
68 __this_cpu_write((fpuemustats).abs_s, 0);
69 __this_cpu_write((fpuemustats).abs_d, 0);
70 __this_cpu_write((fpuemustats).add_s, 0);
71 __this_cpu_write((fpuemustats).add_d, 0);
72 __this_cpu_write((fpuemustats).bc1eqz, 0);
73 __this_cpu_write((fpuemustats).bc1nez, 0);
74 __this_cpu_write((fpuemustats).ceil_w_s, 0);
75 __this_cpu_write((fpuemustats).ceil_w_d, 0);
76 __this_cpu_write((fpuemustats).ceil_l_s, 0);
77 __this_cpu_write((fpuemustats).ceil_l_d, 0);
78 __this_cpu_write((fpuemustats).class_s, 0);
79 __this_cpu_write((fpuemustats).class_d, 0);
80 __this_cpu_write((fpuemustats).cmp_af_s, 0);
81 __this_cpu_write((fpuemustats).cmp_af_d, 0);
82 __this_cpu_write((fpuemustats).cmp_eq_s, 0);
83 __this_cpu_write((fpuemustats).cmp_eq_d, 0);
84 __this_cpu_write((fpuemustats).cmp_le_s, 0);
85 __this_cpu_write((fpuemustats).cmp_le_d, 0);
86 __this_cpu_write((fpuemustats).cmp_lt_s, 0);
87 __this_cpu_write((fpuemustats).cmp_lt_d, 0);
88 __this_cpu_write((fpuemustats).cmp_ne_s, 0);
89 __this_cpu_write((fpuemustats).cmp_ne_d, 0);
90 __this_cpu_write((fpuemustats).cmp_or_s, 0);
91 __this_cpu_write((fpuemustats).cmp_or_d, 0);
92 __this_cpu_write((fpuemustats).cmp_ueq_s, 0);
93 __this_cpu_write((fpuemustats).cmp_ueq_d, 0);
94 __this_cpu_write((fpuemustats).cmp_ule_s, 0);
95 __this_cpu_write((fpuemustats).cmp_ule_d, 0);
96 __this_cpu_write((fpuemustats).cmp_ult_s, 0);
97 __this_cpu_write((fpuemustats).cmp_ult_d, 0);
98 __this_cpu_write((fpuemustats).cmp_un_s, 0);
99 __this_cpu_write((fpuemustats).cmp_un_d, 0);
100 __this_cpu_write((fpuemustats).cmp_une_s, 0);
101 __this_cpu_write((fpuemustats).cmp_une_d, 0);
102 __this_cpu_write((fpuemustats).cmp_saf_s, 0);
103 __this_cpu_write((fpuemustats).cmp_saf_d, 0);
104 __this_cpu_write((fpuemustats).cmp_seq_s, 0);
105 __this_cpu_write((fpuemustats).cmp_seq_d, 0);
106 __this_cpu_write((fpuemustats).cmp_sle_s, 0);
107 __this_cpu_write((fpuemustats).cmp_sle_d, 0);
108 __this_cpu_write((fpuemustats).cmp_slt_s, 0);
109 __this_cpu_write((fpuemustats).cmp_slt_d, 0);
110 __this_cpu_write((fpuemustats).cmp_sne_s, 0);
111 __this_cpu_write((fpuemustats).cmp_sne_d, 0);
112 __this_cpu_write((fpuemustats).cmp_sor_s, 0);
113 __this_cpu_write((fpuemustats).cmp_sor_d, 0);
114 __this_cpu_write((fpuemustats).cmp_sueq_s, 0);
115 __this_cpu_write((fpuemustats).cmp_sueq_d, 0);
116 __this_cpu_write((fpuemustats).cmp_sule_s, 0);
117 __this_cpu_write((fpuemustats).cmp_sule_d, 0);
118 __this_cpu_write((fpuemustats).cmp_sult_s, 0);
119 __this_cpu_write((fpuemustats).cmp_sult_d, 0);
120 __this_cpu_write((fpuemustats).cmp_sun_s, 0);
121 __this_cpu_write((fpuemustats).cmp_sun_d, 0);
122 __this_cpu_write((fpuemustats).cmp_sune_s, 0);
123 __this_cpu_write((fpuemustats).cmp_sune_d, 0);
124 __this_cpu_write((fpuemustats).cvt_d_l, 0);
125 __this_cpu_write((fpuemustats).cvt_d_s, 0);
126 __this_cpu_write((fpuemustats).cvt_d_w, 0);
127 __this_cpu_write((fpuemustats).cvt_l_s, 0);
128 __this_cpu_write((fpuemustats).cvt_l_d, 0);
129 __this_cpu_write((fpuemustats).cvt_s_d, 0);
130 __this_cpu_write((fpuemustats).cvt_s_l, 0);
131 __this_cpu_write((fpuemustats).cvt_s_w, 0);
132 __this_cpu_write((fpuemustats).cvt_w_s, 0);
133 __this_cpu_write((fpuemustats).cvt_w_d, 0);
134 __this_cpu_write((fpuemustats).div_s, 0);
135 __this_cpu_write((fpuemustats).div_d, 0);
136 __this_cpu_write((fpuemustats).floor_w_s, 0);
137 __this_cpu_write((fpuemustats).floor_w_d, 0);
138 __this_cpu_write((fpuemustats).floor_l_s, 0);
139 __this_cpu_write((fpuemustats).floor_l_d, 0);
140 __this_cpu_write((fpuemustats).maddf_s, 0);
141 __this_cpu_write((fpuemustats).maddf_d, 0);
142 __this_cpu_write((fpuemustats).max_s, 0);
143 __this_cpu_write((fpuemustats).max_d, 0);
144 __this_cpu_write((fpuemustats).maxa_s, 0);
145 __this_cpu_write((fpuemustats).maxa_d, 0);
146 __this_cpu_write((fpuemustats).min_s, 0);
147 __this_cpu_write((fpuemustats).min_d, 0);
148 __this_cpu_write((fpuemustats).mina_s, 0);
149 __this_cpu_write((fpuemustats).mina_d, 0);
150 __this_cpu_write((fpuemustats).mov_s, 0);
151 __this_cpu_write((fpuemustats).mov_d, 0);
152 __this_cpu_write((fpuemustats).msubf_s, 0);
153 __this_cpu_write((fpuemustats).msubf_d, 0);
154 __this_cpu_write((fpuemustats).mul_s, 0);
155 __this_cpu_write((fpuemustats).mul_d, 0);
156 __this_cpu_write((fpuemustats).neg_s, 0);
157 __this_cpu_write((fpuemustats).neg_d, 0);
158 __this_cpu_write((fpuemustats).recip_s, 0);
159 __this_cpu_write((fpuemustats).recip_d, 0);
160 __this_cpu_write((fpuemustats).rint_s, 0);
161 __this_cpu_write((fpuemustats).rint_d, 0);
162 __this_cpu_write((fpuemustats).round_w_s, 0);
163 __this_cpu_write((fpuemustats).round_w_d, 0);
164 __this_cpu_write((fpuemustats).round_l_s, 0);
165 __this_cpu_write((fpuemustats).round_l_d, 0);
166 __this_cpu_write((fpuemustats).rsqrt_s, 0);
167 __this_cpu_write((fpuemustats).rsqrt_d, 0);
168 __this_cpu_write((fpuemustats).sel_s, 0);
169 __this_cpu_write((fpuemustats).sel_d, 0);
170 __this_cpu_write((fpuemustats).seleqz_s, 0);
171 __this_cpu_write((fpuemustats).seleqz_d, 0);
172 __this_cpu_write((fpuemustats).selnez_s, 0);
173 __this_cpu_write((fpuemustats).selnez_d, 0);
174 __this_cpu_write((fpuemustats).sqrt_s, 0);
175 __this_cpu_write((fpuemustats).sqrt_d, 0);
176 __this_cpu_write((fpuemustats).sub_s, 0);
177 __this_cpu_write((fpuemustats).sub_d, 0);
178 __this_cpu_write((fpuemustats).trunc_w_s, 0);
179 __this_cpu_write((fpuemustats).trunc_w_d, 0);
180 __this_cpu_write((fpuemustats).trunc_l_s, 0);
181 __this_cpu_write((fpuemustats).trunc_l_d, 0);
182
183 return 0;
184}
185
186DEFINE_SHOW_ATTRIBUTE(fpuemustats_clear);
187
188static int __init debugfs_fpuemu(void)
189{
190 struct dentry *fpuemu_debugfs_base_dir;
191 struct dentry *fpuemu_debugfs_inst_dir;
192 char name[32];
193
194 fpuemu_debugfs_base_dir = debugfs_create_dir("fpuemustats",
195 mips_debugfs_dir);
196
197 debugfs_create_file("fpuemustats_clear", 0444, mips_debugfs_dir, NULL,
198 &fpuemustats_clear_fops);
199
200#define FPU_EMU_STAT_OFFSET(m) \
201 offsetof(struct mips_fpu_emulator_stats, m)
202
203#define FPU_STAT_CREATE(m) \
204do { \
205 debugfs_create_file(#m, 0444, fpuemu_debugfs_base_dir, \
206 (void *)FPU_EMU_STAT_OFFSET(m), \
207 &fops_fpuemu_stat); \
208} while (0)
209
210 FPU_STAT_CREATE(emulated);
211 FPU_STAT_CREATE(loads);
212 FPU_STAT_CREATE(stores);
213 FPU_STAT_CREATE(branches);
214 FPU_STAT_CREATE(cp1ops);
215 FPU_STAT_CREATE(cp1xops);
216 FPU_STAT_CREATE(errors);
217 FPU_STAT_CREATE(ieee754_inexact);
218 FPU_STAT_CREATE(ieee754_underflow);
219 FPU_STAT_CREATE(ieee754_overflow);
220 FPU_STAT_CREATE(ieee754_zerodiv);
221 FPU_STAT_CREATE(ieee754_invalidop);
222 FPU_STAT_CREATE(ds_emul);
223
224 fpuemu_debugfs_inst_dir = debugfs_create_dir("instructions",
225 fpuemu_debugfs_base_dir);
226
227#define FPU_STAT_CREATE_EX(m) \
228do { \
229 adjust_instruction_counter_name(name, #m); \
230 \
231 debugfs_create_file(name, 0444, fpuemu_debugfs_inst_dir, \
232 (void *)FPU_EMU_STAT_OFFSET(m), \
233 &fops_fpuemu_stat); \
234} while (0)
235
236 FPU_STAT_CREATE_EX(abs_s);
237 FPU_STAT_CREATE_EX(abs_d);
238 FPU_STAT_CREATE_EX(add_s);
239 FPU_STAT_CREATE_EX(add_d);
240 FPU_STAT_CREATE_EX(bc1eqz);
241 FPU_STAT_CREATE_EX(bc1nez);
242 FPU_STAT_CREATE_EX(ceil_w_s);
243 FPU_STAT_CREATE_EX(ceil_w_d);
244 FPU_STAT_CREATE_EX(ceil_l_s);
245 FPU_STAT_CREATE_EX(ceil_l_d);
246 FPU_STAT_CREATE_EX(class_s);
247 FPU_STAT_CREATE_EX(class_d);
248 FPU_STAT_CREATE_EX(cmp_af_s);
249 FPU_STAT_CREATE_EX(cmp_af_d);
250 FPU_STAT_CREATE_EX(cmp_eq_s);
251 FPU_STAT_CREATE_EX(cmp_eq_d);
252 FPU_STAT_CREATE_EX(cmp_le_s);
253 FPU_STAT_CREATE_EX(cmp_le_d);
254 FPU_STAT_CREATE_EX(cmp_lt_s);
255 FPU_STAT_CREATE_EX(cmp_lt_d);
256 FPU_STAT_CREATE_EX(cmp_ne_s);
257 FPU_STAT_CREATE_EX(cmp_ne_d);
258 FPU_STAT_CREATE_EX(cmp_or_s);
259 FPU_STAT_CREATE_EX(cmp_or_d);
260 FPU_STAT_CREATE_EX(cmp_ueq_s);
261 FPU_STAT_CREATE_EX(cmp_ueq_d);
262 FPU_STAT_CREATE_EX(cmp_ule_s);
263 FPU_STAT_CREATE_EX(cmp_ule_d);
264 FPU_STAT_CREATE_EX(cmp_ult_s);
265 FPU_STAT_CREATE_EX(cmp_ult_d);
266 FPU_STAT_CREATE_EX(cmp_un_s);
267 FPU_STAT_CREATE_EX(cmp_un_d);
268 FPU_STAT_CREATE_EX(cmp_une_s);
269 FPU_STAT_CREATE_EX(cmp_une_d);
270 FPU_STAT_CREATE_EX(cmp_saf_s);
271 FPU_STAT_CREATE_EX(cmp_saf_d);
272 FPU_STAT_CREATE_EX(cmp_seq_s);
273 FPU_STAT_CREATE_EX(cmp_seq_d);
274 FPU_STAT_CREATE_EX(cmp_sle_s);
275 FPU_STAT_CREATE_EX(cmp_sle_d);
276 FPU_STAT_CREATE_EX(cmp_slt_s);
277 FPU_STAT_CREATE_EX(cmp_slt_d);
278 FPU_STAT_CREATE_EX(cmp_sne_s);
279 FPU_STAT_CREATE_EX(cmp_sne_d);
280 FPU_STAT_CREATE_EX(cmp_sor_s);
281 FPU_STAT_CREATE_EX(cmp_sor_d);
282 FPU_STAT_CREATE_EX(cmp_sueq_s);
283 FPU_STAT_CREATE_EX(cmp_sueq_d);
284 FPU_STAT_CREATE_EX(cmp_sule_s);
285 FPU_STAT_CREATE_EX(cmp_sule_d);
286 FPU_STAT_CREATE_EX(cmp_sult_s);
287 FPU_STAT_CREATE_EX(cmp_sult_d);
288 FPU_STAT_CREATE_EX(cmp_sun_s);
289 FPU_STAT_CREATE_EX(cmp_sun_d);
290 FPU_STAT_CREATE_EX(cmp_sune_s);
291 FPU_STAT_CREATE_EX(cmp_sune_d);
292 FPU_STAT_CREATE_EX(cvt_d_l);
293 FPU_STAT_CREATE_EX(cvt_d_s);
294 FPU_STAT_CREATE_EX(cvt_d_w);
295 FPU_STAT_CREATE_EX(cvt_l_s);
296 FPU_STAT_CREATE_EX(cvt_l_d);
297 FPU_STAT_CREATE_EX(cvt_s_d);
298 FPU_STAT_CREATE_EX(cvt_s_l);
299 FPU_STAT_CREATE_EX(cvt_s_w);
300 FPU_STAT_CREATE_EX(cvt_w_s);
301 FPU_STAT_CREATE_EX(cvt_w_d);
302 FPU_STAT_CREATE_EX(div_s);
303 FPU_STAT_CREATE_EX(div_d);
304 FPU_STAT_CREATE_EX(floor_w_s);
305 FPU_STAT_CREATE_EX(floor_w_d);
306 FPU_STAT_CREATE_EX(floor_l_s);
307 FPU_STAT_CREATE_EX(floor_l_d);
308 FPU_STAT_CREATE_EX(maddf_s);
309 FPU_STAT_CREATE_EX(maddf_d);
310 FPU_STAT_CREATE_EX(max_s);
311 FPU_STAT_CREATE_EX(max_d);
312 FPU_STAT_CREATE_EX(maxa_s);
313 FPU_STAT_CREATE_EX(maxa_d);
314 FPU_STAT_CREATE_EX(min_s);
315 FPU_STAT_CREATE_EX(min_d);
316 FPU_STAT_CREATE_EX(mina_s);
317 FPU_STAT_CREATE_EX(mina_d);
318 FPU_STAT_CREATE_EX(mov_s);
319 FPU_STAT_CREATE_EX(mov_d);
320 FPU_STAT_CREATE_EX(msubf_s);
321 FPU_STAT_CREATE_EX(msubf_d);
322 FPU_STAT_CREATE_EX(mul_s);
323 FPU_STAT_CREATE_EX(mul_d);
324 FPU_STAT_CREATE_EX(neg_s);
325 FPU_STAT_CREATE_EX(neg_d);
326 FPU_STAT_CREATE_EX(recip_s);
327 FPU_STAT_CREATE_EX(recip_d);
328 FPU_STAT_CREATE_EX(rint_s);
329 FPU_STAT_CREATE_EX(rint_d);
330 FPU_STAT_CREATE_EX(round_w_s);
331 FPU_STAT_CREATE_EX(round_w_d);
332 FPU_STAT_CREATE_EX(round_l_s);
333 FPU_STAT_CREATE_EX(round_l_d);
334 FPU_STAT_CREATE_EX(rsqrt_s);
335 FPU_STAT_CREATE_EX(rsqrt_d);
336 FPU_STAT_CREATE_EX(sel_s);
337 FPU_STAT_CREATE_EX(sel_d);
338 FPU_STAT_CREATE_EX(seleqz_s);
339 FPU_STAT_CREATE_EX(seleqz_d);
340 FPU_STAT_CREATE_EX(selnez_s);
341 FPU_STAT_CREATE_EX(selnez_d);
342 FPU_STAT_CREATE_EX(sqrt_s);
343 FPU_STAT_CREATE_EX(sqrt_d);
344 FPU_STAT_CREATE_EX(sub_s);
345 FPU_STAT_CREATE_EX(sub_d);
346 FPU_STAT_CREATE_EX(trunc_w_s);
347 FPU_STAT_CREATE_EX(trunc_w_d);
348 FPU_STAT_CREATE_EX(trunc_l_s);
349 FPU_STAT_CREATE_EX(trunc_l_d);
350
351 return 0;
352}
353arch_initcall(debugfs_fpuemu);
diff --git a/arch/mips/math-emu/sp_2008class.c b/arch/mips/math-emu/sp_2008class.c
new file mode 100644
index 000000000..b9adab6c2
--- /dev/null
+++ b/arch/mips/math-emu/sp_2008class.c
@@ -0,0 +1,52 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * IEEE754 floating point arithmetic
4 * single precision: CLASS.f
5 * FPR[fd] = class(FPR[fs])
6 *
7 * MIPS floating point support
8 * Copyright (C) 2015 Imagination Technologies, Ltd.
9 * Author: Markos Chandras <markos.chandras@imgtec.com>
10 */
11
12#include "ieee754sp.h"
13
14int ieee754sp_2008class(union ieee754sp x)
15{
16 COMPXSP;
17
18 EXPLODEXSP;
19
20 /*
21 * 10 bit mask as follows:
22 *
23 * bit0 = SNAN
24 * bit1 = QNAN
25 * bit2 = -INF
26 * bit3 = -NORM
27 * bit4 = -DNORM
28 * bit5 = -ZERO
29 * bit6 = INF
30 * bit7 = NORM
31 * bit8 = DNORM
32 * bit9 = ZERO
33 */
34
35 switch(xc) {
36 case IEEE754_CLASS_SNAN:
37 return 0x01;
38 case IEEE754_CLASS_QNAN:
39 return 0x02;
40 case IEEE754_CLASS_INF:
41 return 0x04 << (xs ? 0 : 4);
42 case IEEE754_CLASS_NORM:
43 return 0x08 << (xs ? 0 : 4);
44 case IEEE754_CLASS_DNORM:
45 return 0x10 << (xs ? 0 : 4);
46 case IEEE754_CLASS_ZERO:
47 return 0x20 << (xs ? 0 : 4);
48 default:
49 pr_err("Unknown class: %d\n", xc);
50 return 0;
51 }
52}
diff --git a/arch/mips/math-emu/sp_add.c b/arch/mips/math-emu/sp_add.c
new file mode 100644
index 000000000..715cd0534
--- /dev/null
+++ b/arch/mips/math-emu/sp_add.c
@@ -0,0 +1,164 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/* IEEE754 floating point arithmetic
3 * single precision
4 */
5/*
6 * MIPS floating point support
7 * Copyright (C) 1994-2000 Algorithmics Ltd.
8 */
9
10#include "ieee754sp.h"
11
12union ieee754sp ieee754sp_add(union ieee754sp x, union ieee754sp y)
13{
14 int s;
15
16 COMPXSP;
17 COMPYSP;
18
19 EXPLODEXSP;
20 EXPLODEYSP;
21
22 ieee754_clearcx();
23
24 FLUSHXSP;
25 FLUSHYSP;
26
27 switch (CLPAIR(xc, yc)) {
28 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
29 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
30 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
31 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
32 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
33 return ieee754sp_nanxcpt(y);
34
35 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
36 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
37 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
38 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
39 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
40 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
41 return ieee754sp_nanxcpt(x);
42
43 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
44 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
45 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
46 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
47 return y;
48
49 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
50 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
51 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
52 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
53 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
54 return x;
55
56
57 /*
58 * Infinity handling
59 */
60 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
61 if (xs == ys)
62 return x;
63 ieee754_setcx(IEEE754_INVALID_OPERATION);
64 return ieee754sp_indef();
65
66 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
67 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
68 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
69 return y;
70
71 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
72 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
73 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
74 return x;
75
76 /*
77 * Zero handling
78 */
79 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
80 if (xs == ys)
81 return x;
82 else
83 return ieee754sp_zero(ieee754_csr.rm == FPU_CSR_RD);
84
85 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
86 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
87 return x;
88
89 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
90 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
91 return y;
92
93 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
94 SPDNORMX;
95 fallthrough;
96 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
97 SPDNORMY;
98 break;
99
100 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
101 SPDNORMX;
102 break;
103
104 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM):
105 break;
106 }
107 assert(xm & SP_HIDDEN_BIT);
108 assert(ym & SP_HIDDEN_BIT);
109
110 /*
111 * Provide guard, round and stick bit space.
112 */
113 xm <<= 3;
114 ym <<= 3;
115
116 if (xe > ye) {
117 /*
118 * Have to shift y fraction right to align.
119 */
120 s = xe - ye;
121 ym = XSPSRS(ym, s);
122 ye += s;
123 } else if (ye > xe) {
124 /*
125 * Have to shift x fraction right to align.
126 */
127 s = ye - xe;
128 xm = XSPSRS(xm, s);
129 xe += s;
130 }
131 assert(xe == ye);
132 assert(xe <= SP_EMAX);
133
134 if (xs == ys) {
135 /*
136 * Generate 28 bit result of adding two 27 bit numbers
137 * leaving result in xm, xs and xe.
138 */
139 xm = xm + ym;
140
141 if (xm >> (SP_FBITS + 1 + 3)) { /* carry out */
142 SPXSRSX1();
143 }
144 } else {
145 if (xm >= ym) {
146 xm = xm - ym;
147 } else {
148 xm = ym - xm;
149 xs = ys;
150 }
151 if (xm == 0)
152 return ieee754sp_zero(ieee754_csr.rm == FPU_CSR_RD);
153
154 /*
155 * Normalize in extended single precision
156 */
157 while ((xm >> (SP_FBITS + 3)) == 0) {
158 xm <<= 1;
159 xe--;
160 }
161 }
162
163 return ieee754sp_format(xs, xe, xm);
164}
diff --git a/arch/mips/math-emu/sp_cmp.c b/arch/mips/math-emu/sp_cmp.c
new file mode 100644
index 000000000..64a37362a
--- /dev/null
+++ b/arch/mips/math-emu/sp_cmp.c
@@ -0,0 +1,47 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/* IEEE754 floating point arithmetic
3 * single precision
4 */
5/*
6 * MIPS floating point support
7 * Copyright (C) 1994-2000 Algorithmics Ltd.
8 */
9
10#include "ieee754sp.h"
11
12int ieee754sp_cmp(union ieee754sp x, union ieee754sp y, int cmp, int sig)
13{
14 int vx;
15 int vy;
16
17 COMPXSP;
18 COMPYSP;
19
20 EXPLODEXSP;
21 EXPLODEYSP;
22 FLUSHXSP;
23 FLUSHYSP;
24 ieee754_clearcx(); /* Even clear inexact flag here */
25
26 if (ieee754_class_nan(xc) || ieee754_class_nan(yc)) {
27 if (sig ||
28 xc == IEEE754_CLASS_SNAN || yc == IEEE754_CLASS_SNAN)
29 ieee754_setcx(IEEE754_INVALID_OPERATION);
30 return (cmp & IEEE754_CUN) != 0;
31 } else {
32 vx = x.bits;
33 vy = y.bits;
34
35 if (vx < 0)
36 vx = -vx ^ SP_SIGN_BIT;
37 if (vy < 0)
38 vy = -vy ^ SP_SIGN_BIT;
39
40 if (vx < vy)
41 return (cmp & IEEE754_CLT) != 0;
42 else if (vx == vy)
43 return (cmp & IEEE754_CEQ) != 0;
44 else
45 return (cmp & IEEE754_CGT) != 0;
46 }
47}
diff --git a/arch/mips/math-emu/sp_div.c b/arch/mips/math-emu/sp_div.c
new file mode 100644
index 000000000..2bfa266fd
--- /dev/null
+++ b/arch/mips/math-emu/sp_div.c
@@ -0,0 +1,142 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/* IEEE754 floating point arithmetic
3 * single precision
4 */
5/*
6 * MIPS floating point support
7 * Copyright (C) 1994-2000 Algorithmics Ltd.
8 */
9
10#include "ieee754sp.h"
11
12union ieee754sp ieee754sp_div(union ieee754sp x, union ieee754sp y)
13{
14 unsigned int rm;
15 int re;
16 unsigned int bm;
17
18 COMPXSP;
19 COMPYSP;
20
21 EXPLODEXSP;
22 EXPLODEYSP;
23
24 ieee754_clearcx();
25
26 FLUSHXSP;
27 FLUSHYSP;
28
29 switch (CLPAIR(xc, yc)) {
30 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
31 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
32 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
33 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
34 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
35 return ieee754sp_nanxcpt(y);
36
37 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
38 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
39 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
40 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
41 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
42 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
43 return ieee754sp_nanxcpt(x);
44
45 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
46 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
47 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
48 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
49 return y;
50
51 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
52 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
53 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
54 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
55 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
56 return x;
57
58
59 /*
60 * Infinity handling
61 */
62 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
63 ieee754_setcx(IEEE754_INVALID_OPERATION);
64 return ieee754sp_indef();
65
66 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
67 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
68 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
69 return ieee754sp_zero(xs ^ ys);
70
71 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
72 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
73 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
74 return ieee754sp_inf(xs ^ ys);
75
76 /*
77 * Zero handling
78 */
79 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
80 ieee754_setcx(IEEE754_INVALID_OPERATION);
81 return ieee754sp_indef();
82
83 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
84 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
85 ieee754_setcx(IEEE754_ZERO_DIVIDE);
86 return ieee754sp_inf(xs ^ ys);
87
88 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
89 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
90 return ieee754sp_zero(xs == ys ? 0 : 1);
91
92 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
93 SPDNORMX;
94 fallthrough;
95 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
96 SPDNORMY;
97 break;
98
99 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
100 SPDNORMX;
101 break;
102
103 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM):
104 break;
105 }
106 assert(xm & SP_HIDDEN_BIT);
107 assert(ym & SP_HIDDEN_BIT);
108
109 /* provide rounding space */
110 xm <<= 3;
111 ym <<= 3;
112
113 /* now the dirty work */
114
115 rm = 0;
116 re = xe - ye;
117
118 for (bm = SP_MBIT(SP_FBITS + 2); bm; bm >>= 1) {
119 if (xm >= ym) {
120 xm -= ym;
121 rm |= bm;
122 if (xm == 0)
123 break;
124 }
125 xm <<= 1;
126 }
127
128 rm <<= 1;
129 if (xm)
130 rm |= 1; /* have remainder, set sticky */
131
132 assert(rm);
133
134 /* normalise rm to rounding precision ?
135 */
136 while ((rm >> (SP_FBITS + 3)) == 0) {
137 rm <<= 1;
138 re--;
139 }
140
141 return ieee754sp_format(xs == ys ? 0 : 1, re, rm);
142}
diff --git a/arch/mips/math-emu/sp_fdp.c b/arch/mips/math-emu/sp_fdp.c
new file mode 100644
index 000000000..56417497c
--- /dev/null
+++ b/arch/mips/math-emu/sp_fdp.c
@@ -0,0 +1,73 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/* IEEE754 floating point arithmetic
3 * single precision
4 */
5/*
6 * MIPS floating point support
7 * Copyright (C) 1994-2000 Algorithmics Ltd.
8 */
9
10#include "ieee754sp.h"
11#include "ieee754dp.h"
12
13static inline union ieee754sp ieee754sp_nan_fdp(int xs, u64 xm)
14{
15 return buildsp(xs, SP_EMAX + 1 + SP_EBIAS,
16 xm >> (DP_FBITS - SP_FBITS));
17}
18
19union ieee754sp ieee754sp_fdp(union ieee754dp x)
20{
21 union ieee754sp y;
22 u32 rm;
23
24 COMPXDP;
25 COMPYSP;
26
27 EXPLODEXDP;
28
29 ieee754_clearcx();
30
31 FLUSHXDP;
32
33 switch (xc) {
34 case IEEE754_CLASS_SNAN:
35 x = ieee754dp_nanxcpt(x);
36 EXPLODEXDP;
37 fallthrough;
38 case IEEE754_CLASS_QNAN:
39 y = ieee754sp_nan_fdp(xs, xm);
40 if (!ieee754_csr.nan2008) {
41 EXPLODEYSP;
42 if (!ieee754_class_nan(yc))
43 y = ieee754sp_indef();
44 }
45 return y;
46
47 case IEEE754_CLASS_INF:
48 return ieee754sp_inf(xs);
49
50 case IEEE754_CLASS_ZERO:
51 return ieee754sp_zero(xs);
52
53 case IEEE754_CLASS_DNORM:
54 /* can't possibly be sp representable */
55 ieee754_setcx(IEEE754_UNDERFLOW);
56 ieee754_setcx(IEEE754_INEXACT);
57 if ((ieee754_csr.rm == FPU_CSR_RU && !xs) ||
58 (ieee754_csr.rm == FPU_CSR_RD && xs))
59 return ieee754sp_mind(xs);
60 return ieee754sp_zero(xs);
61
62 case IEEE754_CLASS_NORM:
63 break;
64 }
65
66 /*
67 * Convert from DP_FBITS to SP_FBITS+3 with sticky right shift.
68 */
69 rm = (xm >> (DP_FBITS - (SP_FBITS + 3))) |
70 ((xm << (64 - (DP_FBITS - (SP_FBITS + 3)))) != 0);
71
72 return ieee754sp_format(xs, xe, rm);
73}
diff --git a/arch/mips/math-emu/sp_fint.c b/arch/mips/math-emu/sp_fint.c
new file mode 100644
index 000000000..6068e3caa
--- /dev/null
+++ b/arch/mips/math-emu/sp_fint.c
@@ -0,0 +1,53 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/* IEEE754 floating point arithmetic
3 * single precision
4 */
5/*
6 * MIPS floating point support
7 * Copyright (C) 1994-2000 Algorithmics Ltd.
8 */
9
10#include "ieee754sp.h"
11
12union ieee754sp ieee754sp_fint(int x)
13{
14 unsigned int xm;
15 int xe;
16 int xs;
17
18 ieee754_clearcx();
19
20 if (x == 0)
21 return ieee754sp_zero(0);
22 if (x == 1 || x == -1)
23 return ieee754sp_one(x < 0);
24 if (x == 10 || x == -10)
25 return ieee754sp_ten(x < 0);
26
27 xs = (x < 0);
28 if (xs) {
29 if (x == (1 << 31))
30 xm = ((unsigned) 1 << 31); /* max neg can't be safely negated */
31 else
32 xm = -x;
33 } else {
34 xm = x;
35 }
36 xe = SP_FBITS + 3;
37
38 if (xm >> (SP_FBITS + 1 + 3)) {
39 /* shunt out overflow bits
40 */
41 while (xm >> (SP_FBITS + 1 + 3)) {
42 SPXSRSX1();
43 }
44 } else {
45 /* normalize in grs extended single precision
46 */
47 while ((xm >> (SP_FBITS + 3)) == 0) {
48 xm <<= 1;
49 xe--;
50 }
51 }
52 return ieee754sp_format(xs, xe, xm);
53}
diff --git a/arch/mips/math-emu/sp_flong.c b/arch/mips/math-emu/sp_flong.c
new file mode 100644
index 000000000..1b223fb5a
--- /dev/null
+++ b/arch/mips/math-emu/sp_flong.c
@@ -0,0 +1,52 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/* IEEE754 floating point arithmetic
3 * single precision
4 */
5/*
6 * MIPS floating point support
7 * Copyright (C) 1994-2000 Algorithmics Ltd.
8 */
9
10#include "ieee754sp.h"
11
12union ieee754sp ieee754sp_flong(s64 x)
13{
14 u64 xm; /* <--- need 64-bit mantissa temp */
15 int xe;
16 int xs;
17
18 ieee754_clearcx();
19
20 if (x == 0)
21 return ieee754sp_zero(0);
22 if (x == 1 || x == -1)
23 return ieee754sp_one(x < 0);
24 if (x == 10 || x == -10)
25 return ieee754sp_ten(x < 0);
26
27 xs = (x < 0);
28 if (xs) {
29 if (x == (1ULL << 63))
30 xm = (1ULL << 63); /* max neg can't be safely negated */
31 else
32 xm = -x;
33 } else {
34 xm = x;
35 }
36 xe = SP_FBITS + 3;
37
38 if (xm >> (SP_FBITS + 1 + 3)) {
39 /* shunt out overflow bits
40 */
41 while (xm >> (SP_FBITS + 1 + 3)) {
42 SPXSRSX1();
43 }
44 } else {
45 /* normalize in grs extended single precision */
46 while ((xm >> (SP_FBITS + 3)) == 0) {
47 xm <<= 1;
48 xe--;
49 }
50 }
51 return ieee754sp_format(xs, xe, xm);
52}
diff --git a/arch/mips/math-emu/sp_fmax.c b/arch/mips/math-emu/sp_fmax.c
new file mode 100644
index 000000000..3fb16a1df
--- /dev/null
+++ b/arch/mips/math-emu/sp_fmax.c
@@ -0,0 +1,252 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * IEEE754 floating point arithmetic
4 * single precision: MAX{,A}.f
5 * MAX : Scalar Floating-Point Maximum
6 * MAXA: Scalar Floating-Point argument with Maximum Absolute Value
7 *
8 * MAX.S : FPR[fd] = maxNum(FPR[fs],FPR[ft])
9 * MAXA.S: FPR[fd] = maxNumMag(FPR[fs],FPR[ft])
10 *
11 * MIPS floating point support
12 * Copyright (C) 2015 Imagination Technologies, Ltd.
13 * Author: Markos Chandras <markos.chandras@imgtec.com>
14 */
15
16#include "ieee754sp.h"
17
18union ieee754sp ieee754sp_fmax(union ieee754sp x, union ieee754sp y)
19{
20 COMPXSP;
21 COMPYSP;
22
23 EXPLODEXSP;
24 EXPLODEYSP;
25
26 FLUSHXSP;
27 FLUSHYSP;
28
29 ieee754_clearcx();
30
31 switch (CLPAIR(xc, yc)) {
32 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
33 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
34 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
35 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
36 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
37 return ieee754sp_nanxcpt(y);
38
39 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
40 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
41 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
42 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
43 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
44 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
45 return ieee754sp_nanxcpt(x);
46
47 /*
48 * Quiet NaN handling
49 */
50
51 /*
52 * The case of both inputs quiet NaNs
53 */
54 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
55 return x;
56
57 /*
58 * The cases of exactly one input quiet NaN (numbers
59 * are here preferred as returned values to NaNs)
60 */
61 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
62 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
63 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
64 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
65 return x;
66
67 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
68 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
69 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
70 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
71 return y;
72
73 /*
74 * Infinity and zero handling
75 */
76 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
77 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
78 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
79 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
80 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
81 return xs ? y : x;
82
83 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
84 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
85 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
86 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
87 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
88 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
89 return ys ? x : y;
90
91 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
92 return ieee754sp_zero(xs & ys);
93
94 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
95 SPDNORMX;
96 fallthrough;
97 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
98 SPDNORMY;
99 break;
100
101 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
102 SPDNORMX;
103 }
104
105 /* Finally get to do some computation */
106
107 assert(xm & SP_HIDDEN_BIT);
108 assert(ym & SP_HIDDEN_BIT);
109
110 /* Compare signs */
111 if (xs > ys)
112 return y;
113 else if (xs < ys)
114 return x;
115
116 /* Signs of inputs are equal, let's compare exponents */
117 if (xs == 0) {
118 /* Inputs are both positive */
119 if (xe > ye)
120 return x;
121 else if (xe < ye)
122 return y;
123 } else {
124 /* Inputs are both negative */
125 if (xe > ye)
126 return y;
127 else if (xe < ye)
128 return x;
129 }
130
131 /* Signs and exponents of inputs are equal, let's compare mantissas */
132 if (xs == 0) {
133 /* Inputs are both positive, with equal signs and exponents */
134 if (xm <= ym)
135 return y;
136 return x;
137 }
138 /* Inputs are both negative, with equal signs and exponents */
139 if (xm <= ym)
140 return x;
141 return y;
142}
143
144union ieee754sp ieee754sp_fmaxa(union ieee754sp x, union ieee754sp y)
145{
146 COMPXSP;
147 COMPYSP;
148
149 EXPLODEXSP;
150 EXPLODEYSP;
151
152 FLUSHXSP;
153 FLUSHYSP;
154
155 ieee754_clearcx();
156
157 switch (CLPAIR(xc, yc)) {
158 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
159 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
160 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
161 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
162 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
163 return ieee754sp_nanxcpt(y);
164
165 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
166 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
167 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
168 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
169 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
170 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
171 return ieee754sp_nanxcpt(x);
172
173 /*
174 * Quiet NaN handling
175 */
176
177 /*
178 * The case of both inputs quiet NaNs
179 */
180 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
181 return x;
182
183 /*
184 * The cases of exactly one input quiet NaN (numbers
185 * are here preferred as returned values to NaNs)
186 */
187 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
188 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
189 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
190 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
191 return x;
192
193 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
194 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
195 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
196 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
197 return y;
198
199 /*
200 * Infinity and zero handling
201 */
202 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
203 return ieee754sp_inf(xs & ys);
204
205 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
206 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
207 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
208 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
209 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
210 return x;
211
212 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
213 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
214 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
215 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
216 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
217 return y;
218
219 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
220 return ieee754sp_zero(xs & ys);
221
222 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
223 SPDNORMX;
224 fallthrough;
225 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
226 SPDNORMY;
227 break;
228
229 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
230 SPDNORMX;
231 }
232
233 /* Finally get to do some computation */
234
235 assert(xm & SP_HIDDEN_BIT);
236 assert(ym & SP_HIDDEN_BIT);
237
238 /* Compare exponent */
239 if (xe > ye)
240 return x;
241 else if (xe < ye)
242 return y;
243
244 /* Compare mantissa */
245 if (xm < ym)
246 return y;
247 else if (xm > ym)
248 return x;
249 else if (xs == 0)
250 return x;
251 return y;
252}
diff --git a/arch/mips/math-emu/sp_fmin.c b/arch/mips/math-emu/sp_fmin.c
new file mode 100644
index 000000000..ad2599d4a
--- /dev/null
+++ b/arch/mips/math-emu/sp_fmin.c
@@ -0,0 +1,252 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * IEEE754 floating point arithmetic
4 * single precision: MIN{,A}.f
5 * MIN : Scalar Floating-Point Minimum
6 * MINA: Scalar Floating-Point argument with Minimum Absolute Value
7 *
8 * MIN.S : FPR[fd] = minNum(FPR[fs],FPR[ft])
9 * MINA.S: FPR[fd] = maxNumMag(FPR[fs],FPR[ft])
10 *
11 * MIPS floating point support
12 * Copyright (C) 2015 Imagination Technologies, Ltd.
13 * Author: Markos Chandras <markos.chandras@imgtec.com>
14 */
15
16#include "ieee754sp.h"
17
18union ieee754sp ieee754sp_fmin(union ieee754sp x, union ieee754sp y)
19{
20 COMPXSP;
21 COMPYSP;
22
23 EXPLODEXSP;
24 EXPLODEYSP;
25
26 FLUSHXSP;
27 FLUSHYSP;
28
29 ieee754_clearcx();
30
31 switch (CLPAIR(xc, yc)) {
32 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
33 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
34 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
35 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
36 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
37 return ieee754sp_nanxcpt(y);
38
39 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
40 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
41 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
42 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
43 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
44 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
45 return ieee754sp_nanxcpt(x);
46
47 /*
48 * Quiet NaN handling
49 */
50
51 /*
52 * The case of both inputs quiet NaNs
53 */
54 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
55 return x;
56
57 /*
58 * The cases of exactly one input quiet NaN (numbers
59 * are here preferred as returned values to NaNs)
60 */
61 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
62 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
63 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
64 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
65 return x;
66
67 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
68 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
69 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
70 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
71 return y;
72
73 /*
74 * Infinity and zero handling
75 */
76 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
77 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
78 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
79 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
80 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
81 return xs ? x : y;
82
83 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
84 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
85 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
86 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
87 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
88 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
89 return ys ? y : x;
90
91 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
92 return ieee754sp_zero(xs | ys);
93
94 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
95 SPDNORMX;
96 fallthrough;
97 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
98 SPDNORMY;
99 break;
100
101 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
102 SPDNORMX;
103 }
104
105 /* Finally get to do some computation */
106
107 assert(xm & SP_HIDDEN_BIT);
108 assert(ym & SP_HIDDEN_BIT);
109
110 /* Compare signs */
111 if (xs > ys)
112 return x;
113 else if (xs < ys)
114 return y;
115
116 /* Signs of inputs are the same, let's compare exponents */
117 if (xs == 0) {
118 /* Inputs are both positive */
119 if (xe > ye)
120 return y;
121 else if (xe < ye)
122 return x;
123 } else {
124 /* Inputs are both negative */
125 if (xe > ye)
126 return x;
127 else if (xe < ye)
128 return y;
129 }
130
131 /* Signs and exponents of inputs are equal, let's compare mantissas */
132 if (xs == 0) {
133 /* Inputs are both positive, with equal signs and exponents */
134 if (xm <= ym)
135 return x;
136 return y;
137 }
138 /* Inputs are both negative, with equal signs and exponents */
139 if (xm <= ym)
140 return y;
141 return x;
142}
143
144union ieee754sp ieee754sp_fmina(union ieee754sp x, union ieee754sp y)
145{
146 COMPXSP;
147 COMPYSP;
148
149 EXPLODEXSP;
150 EXPLODEYSP;
151
152 FLUSHXSP;
153 FLUSHYSP;
154
155 ieee754_clearcx();
156
157 switch (CLPAIR(xc, yc)) {
158 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
159 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
160 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
161 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
162 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
163 return ieee754sp_nanxcpt(y);
164
165 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
166 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
167 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
168 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
169 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
170 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
171 return ieee754sp_nanxcpt(x);
172
173 /*
174 * Quiet NaN handling
175 */
176
177 /*
178 * The case of both inputs quiet NaNs
179 */
180 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
181 return x;
182
183 /*
184 * The cases of exactly one input quiet NaN (numbers
185 * are here preferred as returned values to NaNs)
186 */
187 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
188 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
189 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
190 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
191 return x;
192
193 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
194 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
195 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
196 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
197 return y;
198
199 /*
200 * Infinity and zero handling
201 */
202 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
203 return ieee754sp_inf(xs | ys);
204
205 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
206 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
207 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
208 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
209 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
210 return y;
211
212 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
213 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
214 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
215 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
216 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
217 return x;
218
219 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
220 return ieee754sp_zero(xs | ys);
221
222 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
223 SPDNORMX;
224 fallthrough;
225 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
226 SPDNORMY;
227 break;
228
229 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
230 SPDNORMX;
231 }
232
233 /* Finally get to do some computation */
234
235 assert(xm & SP_HIDDEN_BIT);
236 assert(ym & SP_HIDDEN_BIT);
237
238 /* Compare exponent */
239 if (xe > ye)
240 return y;
241 else if (xe < ye)
242 return x;
243
244 /* Compare mantissa */
245 if (xm < ym)
246 return x;
247 else if (xm > ym)
248 return y;
249 else if (xs == 1)
250 return x;
251 return y;
252}
diff --git a/arch/mips/math-emu/sp_maddf.c b/arch/mips/math-emu/sp_maddf.c
new file mode 100644
index 000000000..473ee222d
--- /dev/null
+++ b/arch/mips/math-emu/sp_maddf.c
@@ -0,0 +1,278 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * IEEE754 floating point arithmetic
4 * single precision: MADDF.f (Fused Multiply Add)
5 * MADDF.fmt: FPR[fd] = FPR[fd] + (FPR[fs] x FPR[ft])
6 *
7 * MIPS floating point support
8 * Copyright (C) 2015 Imagination Technologies, Ltd.
9 * Author: Markos Chandras <markos.chandras@imgtec.com>
10 */
11
12#include "ieee754sp.h"
13
14
15static union ieee754sp _sp_maddf(union ieee754sp z, union ieee754sp x,
16 union ieee754sp y, enum maddf_flags flags)
17{
18 int re;
19 int rs;
20 unsigned int rm;
21 u64 rm64;
22 u64 zm64;
23 int s;
24
25 COMPXSP;
26 COMPYSP;
27 COMPZSP;
28
29 EXPLODEXSP;
30 EXPLODEYSP;
31 EXPLODEZSP;
32
33 FLUSHXSP;
34 FLUSHYSP;
35 FLUSHZSP;
36
37 ieee754_clearcx();
38
39 rs = xs ^ ys;
40 if (flags & MADDF_NEGATE_PRODUCT)
41 rs ^= 1;
42 if (flags & MADDF_NEGATE_ADDITION)
43 zs ^= 1;
44
45 /*
46 * Handle the cases when at least one of x, y or z is a NaN.
47 * Order of precedence is sNaN, qNaN and z, x, y.
48 */
49 if (zc == IEEE754_CLASS_SNAN)
50 return ieee754sp_nanxcpt(z);
51 if (xc == IEEE754_CLASS_SNAN)
52 return ieee754sp_nanxcpt(x);
53 if (yc == IEEE754_CLASS_SNAN)
54 return ieee754sp_nanxcpt(y);
55 if (zc == IEEE754_CLASS_QNAN)
56 return z;
57 if (xc == IEEE754_CLASS_QNAN)
58 return x;
59 if (yc == IEEE754_CLASS_QNAN)
60 return y;
61
62 if (zc == IEEE754_CLASS_DNORM)
63 SPDNORMZ;
64 /* ZERO z cases are handled separately below */
65
66 switch (CLPAIR(xc, yc)) {
67
68
69 /*
70 * Infinity handling
71 */
72 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
73 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
74 ieee754_setcx(IEEE754_INVALID_OPERATION);
75 return ieee754sp_indef();
76
77 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
78 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
79 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
80 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
81 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
82 if ((zc == IEEE754_CLASS_INF) && (zs != rs)) {
83 /*
84 * Cases of addition of infinities with opposite signs
85 * or subtraction of infinities with same signs.
86 */
87 ieee754_setcx(IEEE754_INVALID_OPERATION);
88 return ieee754sp_indef();
89 }
90 /*
91 * z is here either not an infinity, or an infinity having the
92 * same sign as product (x*y). The result must be an infinity,
93 * and its sign is determined only by the sign of product (x*y).
94 */
95 return ieee754sp_inf(rs);
96
97 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
98 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
99 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
100 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
101 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
102 if (zc == IEEE754_CLASS_INF)
103 return ieee754sp_inf(zs);
104 if (zc == IEEE754_CLASS_ZERO) {
105 /* Handle cases +0 + (-0) and similar ones. */
106 if (zs == rs)
107 /*
108 * Cases of addition of zeros of equal signs
109 * or subtraction of zeroes of opposite signs.
110 * The sign of the resulting zero is in any
111 * such case determined only by the sign of z.
112 */
113 return z;
114
115 return ieee754sp_zero(ieee754_csr.rm == FPU_CSR_RD);
116 }
117 /* x*y is here 0, and z is not 0, so just return z */
118 return z;
119
120 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
121 SPDNORMX;
122 fallthrough;
123 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
124 if (zc == IEEE754_CLASS_INF)
125 return ieee754sp_inf(zs);
126 SPDNORMY;
127 break;
128
129 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
130 if (zc == IEEE754_CLASS_INF)
131 return ieee754sp_inf(zs);
132 SPDNORMX;
133 break;
134
135 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM):
136 if (zc == IEEE754_CLASS_INF)
137 return ieee754sp_inf(zs);
138 /* continue to real computations */
139 }
140
141 /* Finally get to do some computation */
142
143 /*
144 * Do the multiplication bit first
145 *
146 * rm = xm * ym, re = xe + ye basically
147 *
148 * At this point xm and ym should have been normalized.
149 */
150
151 /* rm = xm * ym, re = xe+ye basically */
152 assert(xm & SP_HIDDEN_BIT);
153 assert(ym & SP_HIDDEN_BIT);
154
155 re = xe + ye;
156
157 /* Multiple 24 bit xm and ym to give 48 bit results */
158 rm64 = (uint64_t)xm * ym;
159
160 /* Shunt to top of word */
161 rm64 = rm64 << 16;
162
163 /* Put explicit bit at bit 62 if necessary */
164 if ((int64_t) rm64 < 0) {
165 rm64 = rm64 >> 1;
166 re++;
167 }
168
169 assert(rm64 & (1 << 62));
170
171 if (zc == IEEE754_CLASS_ZERO) {
172 /*
173 * Move explicit bit from bit 62 to bit 26 since the
174 * ieee754sp_format code expects the mantissa to be
175 * 27 bits wide (24 + 3 rounding bits).
176 */
177 rm = XSPSRS64(rm64, (62 - 26));
178 return ieee754sp_format(rs, re, rm);
179 }
180
181 /* Move explicit bit from bit 23 to bit 62 */
182 zm64 = (uint64_t)zm << (62 - 23);
183 assert(zm64 & (1 << 62));
184
185 /* Make the exponents the same */
186 if (ze > re) {
187 /*
188 * Have to shift r fraction right to align.
189 */
190 s = ze - re;
191 rm64 = XSPSRS64(rm64, s);
192 re += s;
193 } else if (re > ze) {
194 /*
195 * Have to shift z fraction right to align.
196 */
197 s = re - ze;
198 zm64 = XSPSRS64(zm64, s);
199 ze += s;
200 }
201 assert(ze == re);
202 assert(ze <= SP_EMAX);
203
204 /* Do the addition */
205 if (zs == rs) {
206 /*
207 * Generate 64 bit result by adding two 63 bit numbers
208 * leaving result in zm64, zs and ze.
209 */
210 zm64 = zm64 + rm64;
211 if ((int64_t)zm64 < 0) { /* carry out */
212 zm64 = XSPSRS1(zm64);
213 ze++;
214 }
215 } else {
216 if (zm64 >= rm64) {
217 zm64 = zm64 - rm64;
218 } else {
219 zm64 = rm64 - zm64;
220 zs = rs;
221 }
222 if (zm64 == 0)
223 return ieee754sp_zero(ieee754_csr.rm == FPU_CSR_RD);
224
225 /*
226 * Put explicit bit at bit 62 if necessary.
227 */
228 while ((zm64 >> 62) == 0) {
229 zm64 <<= 1;
230 ze--;
231 }
232 }
233
234 /*
235 * Move explicit bit from bit 62 to bit 26 since the
236 * ieee754sp_format code expects the mantissa to be
237 * 27 bits wide (24 + 3 rounding bits).
238 */
239 zm = XSPSRS64(zm64, (62 - 26));
240
241 return ieee754sp_format(zs, ze, zm);
242}
243
244union ieee754sp ieee754sp_maddf(union ieee754sp z, union ieee754sp x,
245 union ieee754sp y)
246{
247 return _sp_maddf(z, x, y, 0);
248}
249
250union ieee754sp ieee754sp_msubf(union ieee754sp z, union ieee754sp x,
251 union ieee754sp y)
252{
253 return _sp_maddf(z, x, y, MADDF_NEGATE_PRODUCT);
254}
255
256union ieee754sp ieee754sp_madd(union ieee754sp z, union ieee754sp x,
257 union ieee754sp y)
258{
259 return _sp_maddf(z, x, y, 0);
260}
261
262union ieee754sp ieee754sp_msub(union ieee754sp z, union ieee754sp x,
263 union ieee754sp y)
264{
265 return _sp_maddf(z, x, y, MADDF_NEGATE_ADDITION);
266}
267
268union ieee754sp ieee754sp_nmadd(union ieee754sp z, union ieee754sp x,
269 union ieee754sp y)
270{
271 return _sp_maddf(z, x, y, MADDF_NEGATE_PRODUCT|MADDF_NEGATE_ADDITION);
272}
273
274union ieee754sp ieee754sp_nmsub(union ieee754sp z, union ieee754sp x,
275 union ieee754sp y)
276{
277 return _sp_maddf(z, x, y, MADDF_NEGATE_PRODUCT);
278}
diff --git a/arch/mips/math-emu/sp_mul.c b/arch/mips/math-emu/sp_mul.c
new file mode 100644
index 000000000..26cfd6302
--- /dev/null
+++ b/arch/mips/math-emu/sp_mul.c
@@ -0,0 +1,154 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/* IEEE754 floating point arithmetic
3 * single precision
4 */
5/*
6 * MIPS floating point support
7 * Copyright (C) 1994-2000 Algorithmics Ltd.
8 */
9
10#include "ieee754sp.h"
11
12union ieee754sp ieee754sp_mul(union ieee754sp x, union ieee754sp y)
13{
14 int re;
15 int rs;
16 unsigned int rm;
17 unsigned short lxm;
18 unsigned short hxm;
19 unsigned short lym;
20 unsigned short hym;
21 unsigned int lrm;
22 unsigned int hrm;
23 unsigned int t;
24 unsigned int at;
25
26 COMPXSP;
27 COMPYSP;
28
29 EXPLODEXSP;
30 EXPLODEYSP;
31
32 ieee754_clearcx();
33
34 FLUSHXSP;
35 FLUSHYSP;
36
37 switch (CLPAIR(xc, yc)) {
38 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
39 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
40 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
41 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
42 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
43 return ieee754sp_nanxcpt(y);
44
45 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
46 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
47 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
48 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
49 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
50 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
51 return ieee754sp_nanxcpt(x);
52
53 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
54 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
55 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
56 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
57 return y;
58
59 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
60 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
61 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
62 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
63 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
64 return x;
65
66
67 /*
68 * Infinity handling
69 */
70 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
71 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
72 ieee754_setcx(IEEE754_INVALID_OPERATION);
73 return ieee754sp_indef();
74
75 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
76 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
77 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
78 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
79 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
80 return ieee754sp_inf(xs ^ ys);
81
82 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
83 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
84 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
85 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
86 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
87 return ieee754sp_zero(xs ^ ys);
88
89
90 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
91 SPDNORMX;
92 fallthrough;
93 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
94 SPDNORMY;
95 break;
96
97 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
98 SPDNORMX;
99 break;
100
101 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM):
102 break;
103 }
104 /* rm = xm * ym, re = xe+ye basically */
105 assert(xm & SP_HIDDEN_BIT);
106 assert(ym & SP_HIDDEN_BIT);
107
108 re = xe + ye;
109 rs = xs ^ ys;
110
111 /* shunt to top of word */
112 xm <<= 32 - (SP_FBITS + 1);
113 ym <<= 32 - (SP_FBITS + 1);
114
115 /*
116 * Multiply 32 bits xm, ym to give high 32 bits rm with stickness.
117 */
118 lxm = xm & 0xffff;
119 hxm = xm >> 16;
120 lym = ym & 0xffff;
121 hym = ym >> 16;
122
123 lrm = lxm * lym; /* 16 * 16 => 32 */
124 hrm = hxm * hym; /* 16 * 16 => 32 */
125
126 t = lxm * hym; /* 16 * 16 => 32 */
127 at = lrm + (t << 16);
128 hrm += at < lrm;
129 lrm = at;
130 hrm = hrm + (t >> 16);
131
132 t = hxm * lym; /* 16 * 16 => 32 */
133 at = lrm + (t << 16);
134 hrm += at < lrm;
135 lrm = at;
136 hrm = hrm + (t >> 16);
137
138 rm = hrm | (lrm != 0);
139
140 /*
141 * Sticky shift down to normal rounding precision.
142 */
143 if ((int) rm < 0) {
144 rm = (rm >> (32 - (SP_FBITS + 1 + 3))) |
145 ((rm << (SP_FBITS + 1 + 3)) != 0);
146 re++;
147 } else {
148 rm = (rm >> (32 - (SP_FBITS + 1 + 3 + 1))) |
149 ((rm << (SP_FBITS + 1 + 3 + 1)) != 0);
150 }
151 assert(rm & (SP_HIDDEN_BIT << 3));
152
153 return ieee754sp_format(rs, re, rm);
154}
diff --git a/arch/mips/math-emu/sp_rint.c b/arch/mips/math-emu/sp_rint.c
new file mode 100644
index 000000000..d5f75fe21
--- /dev/null
+++ b/arch/mips/math-emu/sp_rint.c
@@ -0,0 +1,79 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/* IEEE754 floating point arithmetic
3 * single precision
4 */
5/*
6 * MIPS floating point support
7 * Copyright (C) 1994-2000 Algorithmics Ltd.
8 * Copyright (C) 2017 Imagination Technologies, Ltd.
9 * Author: Aleksandar Markovic <aleksandar.markovic@imgtec.com>
10 */
11
12#include "ieee754sp.h"
13
14union ieee754sp ieee754sp_rint(union ieee754sp x)
15{
16 union ieee754sp ret;
17 u32 residue;
18 int sticky;
19 int round;
20 int odd;
21
22 COMPXDP; /* <-- DP needed for 64-bit mantissa tmp */
23
24 ieee754_clearcx();
25
26 EXPLODEXSP;
27 FLUSHXSP;
28
29 if (xc == IEEE754_CLASS_SNAN)
30 return ieee754sp_nanxcpt(x);
31
32 if ((xc == IEEE754_CLASS_QNAN) ||
33 (xc == IEEE754_CLASS_INF) ||
34 (xc == IEEE754_CLASS_ZERO))
35 return x;
36
37 if (xe >= SP_FBITS)
38 return x;
39
40 if (xe < -1) {
41 residue = xm;
42 round = 0;
43 sticky = residue != 0;
44 xm = 0;
45 } else {
46 residue = xm << (xe + 1);
47 residue <<= 31 - SP_FBITS;
48 round = (residue >> 31) != 0;
49 sticky = (residue << 1) != 0;
50 xm >>= SP_FBITS - xe;
51 }
52
53 odd = (xm & 0x1) != 0x0;
54
55 switch (ieee754_csr.rm) {
56 case FPU_CSR_RN: /* toward nearest */
57 if (round && (sticky || odd))
58 xm++;
59 break;
60 case FPU_CSR_RZ: /* toward zero */
61 break;
62 case FPU_CSR_RU: /* toward +infinity */
63 if ((round || sticky) && !xs)
64 xm++;
65 break;
66 case FPU_CSR_RD: /* toward -infinity */
67 if ((round || sticky) && xs)
68 xm++;
69 break;
70 }
71
72 if (round || sticky)
73 ieee754_setcx(IEEE754_INEXACT);
74
75 ret = ieee754sp_flong(xm);
76 SPSIGN(ret) = xs;
77
78 return ret;
79}
diff --git a/arch/mips/math-emu/sp_simple.c b/arch/mips/math-emu/sp_simple.c
new file mode 100644
index 000000000..b9e91da7d
--- /dev/null
+++ b/arch/mips/math-emu/sp_simple.c
@@ -0,0 +1,49 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/* IEEE754 floating point arithmetic
3 * single precision
4 */
5/*
6 * MIPS floating point support
7 * Copyright (C) 1994-2000 Algorithmics Ltd.
8 */
9
10#include "ieee754sp.h"
11
12union ieee754sp ieee754sp_neg(union ieee754sp x)
13{
14 union ieee754sp y;
15
16 if (ieee754_csr.abs2008) {
17 y = x;
18 SPSIGN(y) = !SPSIGN(x);
19 } else {
20 unsigned int oldrm;
21
22 oldrm = ieee754_csr.rm;
23 ieee754_csr.rm = FPU_CSR_RD;
24 y = ieee754sp_sub(ieee754sp_zero(0), x);
25 ieee754_csr.rm = oldrm;
26 }
27 return y;
28}
29
30union ieee754sp ieee754sp_abs(union ieee754sp x)
31{
32 union ieee754sp y;
33
34 if (ieee754_csr.abs2008) {
35 y = x;
36 SPSIGN(y) = 0;
37 } else {
38 unsigned int oldrm;
39
40 oldrm = ieee754_csr.rm;
41 ieee754_csr.rm = FPU_CSR_RD;
42 if (SPSIGN(x))
43 y = ieee754sp_sub(ieee754sp_zero(0), x);
44 else
45 y = ieee754sp_add(ieee754sp_zero(0), x);
46 ieee754_csr.rm = oldrm;
47 }
48 return y;
49}
diff --git a/arch/mips/math-emu/sp_sqrt.c b/arch/mips/math-emu/sp_sqrt.c
new file mode 100644
index 000000000..e9bb60121
--- /dev/null
+++ b/arch/mips/math-emu/sp_sqrt.c
@@ -0,0 +1,103 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/* IEEE754 floating point arithmetic
3 * single precision square root
4 */
5/*
6 * MIPS floating point support
7 * Copyright (C) 1994-2000 Algorithmics Ltd.
8 */
9
10#include "ieee754sp.h"
11
12union ieee754sp ieee754sp_sqrt(union ieee754sp x)
13{
14 int ix, s, q, m, t, i;
15 unsigned int r;
16 COMPXSP;
17
18 /* take care of Inf and NaN */
19
20 EXPLODEXSP;
21 ieee754_clearcx();
22 FLUSHXSP;
23
24 /* x == INF or NAN? */
25 switch (xc) {
26 case IEEE754_CLASS_SNAN:
27 return ieee754sp_nanxcpt(x);
28
29 case IEEE754_CLASS_QNAN:
30 /* sqrt(Nan) = Nan */
31 return x;
32
33 case IEEE754_CLASS_ZERO:
34 /* sqrt(0) = 0 */
35 return x;
36
37 case IEEE754_CLASS_INF:
38 if (xs) {
39 /* sqrt(-Inf) = Nan */
40 ieee754_setcx(IEEE754_INVALID_OPERATION);
41 return ieee754sp_indef();
42 }
43 /* sqrt(+Inf) = Inf */
44 return x;
45
46 case IEEE754_CLASS_DNORM:
47 case IEEE754_CLASS_NORM:
48 if (xs) {
49 /* sqrt(-x) = Nan */
50 ieee754_setcx(IEEE754_INVALID_OPERATION);
51 return ieee754sp_indef();
52 }
53 break;
54 }
55
56 ix = x.bits;
57
58 /* normalize x */
59 m = (ix >> 23);
60 if (m == 0) { /* subnormal x */
61 for (i = 0; (ix & 0x00800000) == 0; i++)
62 ix <<= 1;
63 m -= i - 1;
64 }
65 m -= 127; /* unbias exponent */
66 ix = (ix & 0x007fffff) | 0x00800000;
67 if (m & 1) /* odd m, double x to make it even */
68 ix += ix;
69 m >>= 1; /* m = [m/2] */
70
71 /* generate sqrt(x) bit by bit */
72 ix += ix;
73 s = 0;
74 q = 0; /* q = sqrt(x) */
75 r = 0x01000000; /* r = moving bit from right to left */
76
77 while (r != 0) {
78 t = s + r;
79 if (t <= ix) {
80 s = t + r;
81 ix -= t;
82 q += r;
83 }
84 ix += ix;
85 r >>= 1;
86 }
87
88 if (ix != 0) {
89 ieee754_setcx(IEEE754_INEXACT);
90 switch (ieee754_csr.rm) {
91 case FPU_CSR_RU:
92 q += 2;
93 break;
94 case FPU_CSR_RN:
95 q += (q & 1);
96 break;
97 }
98 }
99 ix = (q >> 1) + 0x3f000000;
100 ix += (m << 23);
101 x.bits = ix;
102 return x;
103}
diff --git a/arch/mips/math-emu/sp_sub.c b/arch/mips/math-emu/sp_sub.c
new file mode 100644
index 000000000..16c8e9ae6
--- /dev/null
+++ b/arch/mips/math-emu/sp_sub.c
@@ -0,0 +1,168 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/* IEEE754 floating point arithmetic
3 * single precision
4 */
5/*
6 * MIPS floating point support
7 * Copyright (C) 1994-2000 Algorithmics Ltd.
8 */
9
10#include "ieee754sp.h"
11
12union ieee754sp ieee754sp_sub(union ieee754sp x, union ieee754sp y)
13{
14 int s;
15
16 COMPXSP;
17 COMPYSP;
18
19 EXPLODEXSP;
20 EXPLODEYSP;
21
22 ieee754_clearcx();
23
24 FLUSHXSP;
25 FLUSHYSP;
26
27 switch (CLPAIR(xc, yc)) {
28 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
29 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
30 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
31 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
32 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
33 return ieee754sp_nanxcpt(y);
34
35 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
36 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
37 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
38 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
39 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
40 case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
41 return ieee754sp_nanxcpt(x);
42
43 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
44 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
45 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
46 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
47 return y;
48
49 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
50 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
51 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
52 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
53 case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
54 return x;
55
56
57 /*
58 * Infinity handling
59 */
60 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
61 if (xs != ys)
62 return x;
63 ieee754_setcx(IEEE754_INVALID_OPERATION);
64 return ieee754sp_indef();
65
66 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
67 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
68 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
69 return ieee754sp_inf(ys ^ 1);
70
71 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
72 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
73 case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
74 return x;
75
76 /*
77 * Zero handling
78 */
79 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
80 if (xs != ys)
81 return x;
82 else
83 return ieee754sp_zero(ieee754_csr.rm == FPU_CSR_RD);
84
85 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
86 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
87 return x;
88
89 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
90 case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
91 /* quick fix up */
92 SPSIGN(y) ^= 1;
93 return y;
94
95 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
96 SPDNORMX;
97 fallthrough;
98 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
99 SPDNORMY;
100 break;
101
102 case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
103 SPDNORMX;
104 break;
105
106 case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM):
107 break;
108 }
109 /* flip sign of y and handle as add */
110 ys ^= 1;
111
112 assert(xm & SP_HIDDEN_BIT);
113 assert(ym & SP_HIDDEN_BIT);
114
115
116 /* provide guard,round and stick bit space */
117 xm <<= 3;
118 ym <<= 3;
119
120 if (xe > ye) {
121 /*
122 * have to shift y fraction right to align
123 */
124 s = xe - ye;
125 ym = XSPSRS(ym, s);
126 ye += s;
127 } else if (ye > xe) {
128 /*
129 * have to shift x fraction right to align
130 */
131 s = ye - xe;
132 xm = XSPSRS(xm, s);
133 xe += s;
134 }
135 assert(xe == ye);
136 assert(xe <= SP_EMAX);
137
138 if (xs == ys) {
139 /* generate 28 bit result of adding two 27 bit numbers
140 */
141 xm = xm + ym;
142
143 if (xm >> (SP_FBITS + 1 + 3)) { /* carry out */
144 SPXSRSX1(); /* shift preserving sticky */
145 }
146 } else {
147 if (xm >= ym) {
148 xm = xm - ym;
149 } else {
150 xm = ym - xm;
151 xs = ys;
152 }
153 if (xm == 0) {
154 if (ieee754_csr.rm == FPU_CSR_RD)
155 return ieee754sp_zero(1); /* round negative inf. => sign = -1 */
156 else
157 return ieee754sp_zero(0); /* other round modes => sign = 1 */
158 }
159 /* normalize to rounding precision
160 */
161 while ((xm >> (SP_FBITS + 3)) == 0) {
162 xm <<= 1;
163 xe--;
164 }
165 }
166
167 return ieee754sp_format(xs, xe, xm);
168}
diff --git a/arch/mips/math-emu/sp_tint.c b/arch/mips/math-emu/sp_tint.c
new file mode 100644
index 000000000..f7a5cf5e1
--- /dev/null
+++ b/arch/mips/math-emu/sp_tint.c
@@ -0,0 +1,100 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/* IEEE754 floating point arithmetic
3 * single precision
4 */
5/*
6 * MIPS floating point support
7 * Copyright (C) 1994-2000 Algorithmics Ltd.
8 */
9
10#include "ieee754sp.h"
11
12int ieee754sp_tint(union ieee754sp x)
13{
14 u32 residue;
15 int round;
16 int sticky;
17 int odd;
18
19 COMPXSP;
20
21 ieee754_clearcx();
22
23 EXPLODEXSP;
24 FLUSHXSP;
25
26 switch (xc) {
27 case IEEE754_CLASS_SNAN:
28 case IEEE754_CLASS_QNAN:
29 ieee754_setcx(IEEE754_INVALID_OPERATION);
30 return ieee754si_indef();
31
32 case IEEE754_CLASS_INF:
33 ieee754_setcx(IEEE754_INVALID_OPERATION);
34 return ieee754si_overflow(xs);
35
36 case IEEE754_CLASS_ZERO:
37 return 0;
38
39 case IEEE754_CLASS_DNORM:
40 case IEEE754_CLASS_NORM:
41 break;
42 }
43 if (xe >= 31) {
44 /* look for valid corner case */
45 if (xe == 31 && xs && xm == SP_HIDDEN_BIT)
46 return -0x80000000;
47 /* Set invalid. We will only use overflow for floating
48 point overflow */
49 ieee754_setcx(IEEE754_INVALID_OPERATION);
50 return ieee754si_overflow(xs);
51 }
52 /* oh gawd */
53 if (xe > SP_FBITS) {
54 xm <<= xe - SP_FBITS;
55 } else {
56 if (xe < -1) {
57 residue = xm;
58 round = 0;
59 sticky = residue != 0;
60 xm = 0;
61 } else {
62 /* Shifting a u32 32 times does not work,
63 * so we do it in two steps. Be aware that xe
64 * may be -1 */
65 residue = xm << (xe + 1);
66 residue <<= 31 - SP_FBITS;
67 round = (residue >> 31) != 0;
68 sticky = (residue << 1) != 0;
69 xm >>= SP_FBITS - xe;
70 }
71 odd = (xm & 0x1) != 0x0;
72 switch (ieee754_csr.rm) {
73 case FPU_CSR_RN:
74 if (round && (sticky || odd))
75 xm++;
76 break;
77 case FPU_CSR_RZ:
78 break;
79 case FPU_CSR_RU: /* toward +Infinity */
80 if ((round || sticky) && !xs)
81 xm++;
82 break;
83 case FPU_CSR_RD: /* toward -Infinity */
84 if ((round || sticky) && xs)
85 xm++;
86 break;
87 }
88 if ((xm >> 31) != 0) {
89 /* This can happen after rounding */
90 ieee754_setcx(IEEE754_INVALID_OPERATION);
91 return ieee754si_overflow(xs);
92 }
93 if (round || sticky)
94 ieee754_setcx(IEEE754_INEXACT);
95 }
96 if (xs)
97 return -xm;
98 else
99 return xm;
100}
diff --git a/arch/mips/math-emu/sp_tlong.c b/arch/mips/math-emu/sp_tlong.c
new file mode 100644
index 000000000..adc191304
--- /dev/null
+++ b/arch/mips/math-emu/sp_tlong.c
@@ -0,0 +1,96 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/* IEEE754 floating point arithmetic
3 * single precision
4 */
5/*
6 * MIPS floating point support
7 * Copyright (C) 1994-2000 Algorithmics Ltd.
8 */
9
10#include "ieee754sp.h"
11
12s64 ieee754sp_tlong(union ieee754sp x)
13{
14 u32 residue;
15 int round;
16 int sticky;
17 int odd;
18
19 COMPXDP; /* <-- need 64-bit mantissa tmp */
20
21 ieee754_clearcx();
22
23 EXPLODEXSP;
24 FLUSHXSP;
25
26 switch (xc) {
27 case IEEE754_CLASS_SNAN:
28 case IEEE754_CLASS_QNAN:
29 ieee754_setcx(IEEE754_INVALID_OPERATION);
30 return ieee754di_indef();
31
32 case IEEE754_CLASS_INF:
33 ieee754_setcx(IEEE754_INVALID_OPERATION);
34 return ieee754di_overflow(xs);
35
36 case IEEE754_CLASS_ZERO:
37 return 0;
38
39 case IEEE754_CLASS_DNORM:
40 case IEEE754_CLASS_NORM:
41 break;
42 }
43 if (xe >= 63) {
44 /* look for valid corner case */
45 if (xe == 63 && xs && xm == SP_HIDDEN_BIT)
46 return -0x8000000000000000LL;
47 /* Set invalid. We will only use overflow for floating
48 point overflow */
49 ieee754_setcx(IEEE754_INVALID_OPERATION);
50 return ieee754di_overflow(xs);
51 }
52 /* oh gawd */
53 if (xe > SP_FBITS) {
54 xm <<= xe - SP_FBITS;
55 } else if (xe < SP_FBITS) {
56 if (xe < -1) {
57 residue = xm;
58 round = 0;
59 sticky = residue != 0;
60 xm = 0;
61 } else {
62 residue = xm << (32 - SP_FBITS + xe);
63 round = (residue >> 31) != 0;
64 sticky = (residue << 1) != 0;
65 xm >>= SP_FBITS - xe;
66 }
67 odd = (xm & 0x1) != 0x0;
68 switch (ieee754_csr.rm) {
69 case FPU_CSR_RN:
70 if (round && (sticky || odd))
71 xm++;
72 break;
73 case FPU_CSR_RZ:
74 break;
75 case FPU_CSR_RU: /* toward +Infinity */
76 if ((round || sticky) && !xs)
77 xm++;
78 break;
79 case FPU_CSR_RD: /* toward -Infinity */
80 if ((round || sticky) && xs)
81 xm++;
82 break;
83 }
84 if ((xm >> 63) != 0) {
85 /* This can happen after rounding */
86 ieee754_setcx(IEEE754_INVALID_OPERATION);
87 return ieee754di_overflow(xs);
88 }
89 if (round || sticky)
90 ieee754_setcx(IEEE754_INEXACT);
91 }
92 if (xs)
93 return -xm;
94 else
95 return xm;
96}