~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/nds32/math-emu/fpuemu.c

Version: ~ [ linux-5.15-rc5 ] ~ [ linux-5.14.11 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.72 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.152 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.210 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.250 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.286 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.288 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 // Copyright (C) 2005-2018 Andes Technology Corporation
  3 
  4 #include <asm/bitfield.h>
  5 #include <asm/uaccess.h>
  6 #include <asm/sfp-machine.h>
  7 #include <asm/fpuemu.h>
  8 #include <asm/nds32_fpu_inst.h>
  9 
 10 #define DPFROMREG(dp, x) (dp = (void *)((unsigned long *)fpu_reg + 2*x))
 11 #ifdef __NDS32_EL__
 12 #define SPFROMREG(sp, x)\
 13         ((sp) = (void *)((unsigned long *)fpu_reg + (x^1)))
 14 #else
 15 #define SPFROMREG(sp, x) ((sp) = (void *)((unsigned long *)fpu_reg + x))
 16 #endif
 17 
 18 #define DEF3OP(name, p, f1, f2) \
 19 void fpemu_##name##p(void *ft, void *fa, void *fb) \
 20 { \
 21         f1(fa, fa, fb); \
 22         f2(ft, ft, fa); \
 23 }
 24 
 25 #define DEF3OPNEG(name, p, f1, f2, f3) \
 26 void fpemu_##name##p(void *ft, void *fa, void *fb) \
 27 { \
 28         f1(fa, fa, fb); \
 29         f2(ft, ft, fa); \
 30         f3(ft, ft); \
 31 }
 32 DEF3OP(fmadd, s, fmuls, fadds);
 33 DEF3OP(fmsub, s, fmuls, fsubs);
 34 DEF3OP(fmadd, d, fmuld, faddd);
 35 DEF3OP(fmsub, d, fmuld, fsubd);
 36 DEF3OPNEG(fnmadd, s, fmuls, fadds, fnegs);
 37 DEF3OPNEG(fnmsub, s, fmuls, fsubs, fnegs);
 38 DEF3OPNEG(fnmadd, d, fmuld, faddd, fnegd);
 39 DEF3OPNEG(fnmsub, d, fmuld, fsubd, fnegd);
 40 
 41 static const unsigned char cmptab[8] = {
 42         SF_CEQ,
 43         SF_CEQ,
 44         SF_CLT,
 45         SF_CLT,
 46         SF_CLT | SF_CEQ,
 47         SF_CLT | SF_CEQ,
 48         SF_CUN,
 49         SF_CUN
 50 };
 51 
 52 enum ARGTYPE {
 53         S1S = 1,
 54         S2S,
 55         S1D,
 56         CS,
 57         D1D,
 58         D2D,
 59         D1S,
 60         CD
 61 };
 62 union func_t {
 63         void (*t)(void *ft, void *fa, void *fb);
 64         void (*b)(void *ft, void *fa);
 65 };
 66 /*
 67  * Emulate a single FPU arithmetic instruction.
 68  */
 69 static int fpu_emu(struct fpu_struct *fpu_reg, unsigned long insn)
 70 {
 71         int rfmt;               /* resulting format */
 72         union func_t func;
 73         int ftype = 0;
 74 
 75         switch (rfmt = NDS32Insn_OPCODE_COP0(insn)) {
 76         case fs1_op:{
 77                         switch (NDS32Insn_OPCODE_BIT69(insn)) {
 78                         case fadds_op:
 79                                 func.t = fadds;
 80                                 ftype = S2S;
 81                                 break;
 82                         case fsubs_op:
 83                                 func.t = fsubs;
 84                                 ftype = S2S;
 85                                 break;
 86                         case fmadds_op:
 87                                 func.t = fpemu_fmadds;
 88                                 ftype = S2S;
 89                                 break;
 90                         case fmsubs_op:
 91                                 func.t = fpemu_fmsubs;
 92                                 ftype = S2S;
 93                                 break;
 94                         case fnmadds_op:
 95                                 func.t = fpemu_fnmadds;
 96                                 ftype = S2S;
 97                                 break;
 98                         case fnmsubs_op:
 99                                 func.t = fpemu_fnmsubs;
100                                 ftype = S2S;
101                                 break;
102                         case fmuls_op:
103                                 func.t = fmuls;
104                                 ftype = S2S;
105                                 break;
106                         case fdivs_op:
107                                 func.t = fdivs;
108                                 ftype = S2S;
109                                 break;
110                         case fs1_f2op_op:
111                                 switch (NDS32Insn_OPCODE_BIT1014(insn)) {
112                                 case fs2d_op:
113                                         func.b = fs2d;
114                                         ftype = S1D;
115                                         break;
116                                 case fs2si_op:
117                                         func.b = fs2si;
118                                         ftype = S1S;
119                                         break;
120                                 case fs2si_z_op:
121                                         func.b = fs2si_z;
122                                         ftype = S1S;
123                                         break;
124                                 case fs2ui_op:
125                                         func.b = fs2ui;
126                                         ftype = S1S;
127                                         break;
128                                 case fs2ui_z_op:
129                                         func.b = fs2ui_z;
130                                         ftype = S1S;
131                                         break;
132                                 case fsi2s_op:
133                                         func.b = fsi2s;
134                                         ftype = S1S;
135                                         break;
136                                 case fui2s_op:
137                                         func.b = fui2s;
138                                         ftype = S1S;
139                                         break;
140                                 case fsqrts_op:
141                                         func.b = fsqrts;
142                                         ftype = S1S;
143                                         break;
144                                 default:
145                                         return SIGILL;
146                                 }
147                                 break;
148                         default:
149                                 return SIGILL;
150                         }
151                         break;
152                 }
153         case fs2_op:
154                 switch (NDS32Insn_OPCODE_BIT69(insn)) {
155                 case fcmpeqs_op:
156                 case fcmpeqs_e_op:
157                 case fcmplts_op:
158                 case fcmplts_e_op:
159                 case fcmples_op:
160                 case fcmples_e_op:
161                 case fcmpuns_op:
162                 case fcmpuns_e_op:
163                         ftype = CS;
164                         break;
165                 default:
166                         return SIGILL;
167                 }
168                 break;
169         case fd1_op:{
170                         switch (NDS32Insn_OPCODE_BIT69(insn)) {
171                         case faddd_op:
172                                 func.t = faddd;
173                                 ftype = D2D;
174                                 break;
175                         case fsubd_op:
176                                 func.t = fsubd;
177                                 ftype = D2D;
178                                 break;
179                         case fmaddd_op:
180                                 func.t = fpemu_fmaddd;
181                                 ftype = D2D;
182                                 break;
183                         case fmsubd_op:
184                                 func.t = fpemu_fmsubd;
185                                 ftype = D2D;
186                                 break;
187                         case fnmaddd_op:
188                                 func.t = fpemu_fnmaddd;
189                                 ftype = D2D;
190                                 break;
191                         case fnmsubd_op:
192                                 func.t = fpemu_fnmsubd;
193                                 ftype = D2D;
194                                 break;
195                         case fmuld_op:
196                                 func.t = fmuld;
197                                 ftype = D2D;
198                                 break;
199                         case fdivd_op:
200                                 func.t = fdivd;
201                                 ftype = D2D;
202                                 break;
203                         case fd1_f2op_op:
204                                 switch (NDS32Insn_OPCODE_BIT1014(insn)) {
205                                 case fd2s_op:
206                                         func.b = fd2s;
207                                         ftype = D1S;
208                                         break;
209                                 case fd2si_op:
210                                         func.b = fd2si;
211                                         ftype = D1S;
212                                         break;
213                                 case fd2si_z_op:
214                                         func.b = fd2si_z;
215                                         ftype = D1S;
216                                         break;
217                                 case fd2ui_op:
218                                         func.b = fd2ui;
219                                         ftype = D1S;
220                                         break;
221                                 case fd2ui_z_op:
222                                         func.b = fd2ui_z;
223                                         ftype = D1S;
224                                         break;
225                                 case fsi2d_op:
226                                         func.b = fsi2d;
227                                         ftype = D1S;
228                                         break;
229                                 case fui2d_op:
230                                         func.b = fui2d;
231                                         ftype = D1S;
232                                         break;
233                                 case fsqrtd_op:
234                                         func.b = fsqrtd;
235                                         ftype = D1D;
236                                         break;
237                                 default:
238                                         return SIGILL;
239                                 }
240                                 break;
241                         default:
242                                 return SIGILL;
243 
244                         }
245                         break;
246                 }
247 
248         case fd2_op:
249                 switch (NDS32Insn_OPCODE_BIT69(insn)) {
250                 case fcmpeqd_op:
251                 case fcmpeqd_e_op:
252                 case fcmpltd_op:
253                 case fcmpltd_e_op:
254                 case fcmpled_op:
255                 case fcmpled_e_op:
256                 case fcmpund_op:
257                 case fcmpund_e_op:
258                         ftype = CD;
259                         break;
260                 default:
261                         return SIGILL;
262                 }
263                 break;
264 
265         default:
266                 return SIGILL;
267         }
268 
269         switch (ftype) {
270         case S1S:{
271                         void *ft, *fa;
272 
273                         SPFROMREG(ft, NDS32Insn_OPCODE_Rt(insn));
274                         SPFROMREG(fa, NDS32Insn_OPCODE_Ra(insn));
275                         func.b(ft, fa);
276                         break;
277                 }
278         case S2S:{
279                         void *ft, *fa, *fb;
280 
281                         SPFROMREG(ft, NDS32Insn_OPCODE_Rt(insn));
282                         SPFROMREG(fa, NDS32Insn_OPCODE_Ra(insn));
283                         SPFROMREG(fb, NDS32Insn_OPCODE_Rb(insn));
284                         func.t(ft, fa, fb);
285                         break;
286                 }
287         case S1D:{
288                         void *ft, *fa;
289 
290                         DPFROMREG(ft, NDS32Insn_OPCODE_Rt(insn));
291                         SPFROMREG(fa, NDS32Insn_OPCODE_Ra(insn));
292                         func.b(ft, fa);
293                         break;
294                 }
295         case CS:{
296                         unsigned int cmpop = NDS32Insn_OPCODE_BIT69(insn);
297                         void *ft, *fa, *fb;
298 
299                         SPFROMREG(ft, NDS32Insn_OPCODE_Rt(insn));
300                         SPFROMREG(fa, NDS32Insn_OPCODE_Ra(insn));
301                         SPFROMREG(fb, NDS32Insn_OPCODE_Rb(insn));
302                         if (cmpop < 0x8) {
303                                 cmpop = cmptab[cmpop];
304                                 fcmps(ft, fa, fb, cmpop);
305                         } else
306                                 return SIGILL;
307                         break;
308                 }
309         case D1D:{
310                         void *ft, *fa;
311 
312                         DPFROMREG(ft, NDS32Insn_OPCODE_Rt(insn));
313                         DPFROMREG(fa, NDS32Insn_OPCODE_Ra(insn));
314                         func.b(ft, fa);
315                         break;
316                 }
317         case D2D:{
318                         void *ft, *fa, *fb;
319 
320                         DPFROMREG(ft, NDS32Insn_OPCODE_Rt(insn));
321                         DPFROMREG(fa, NDS32Insn_OPCODE_Ra(insn));
322                         DPFROMREG(fb, NDS32Insn_OPCODE_Rb(insn));
323                         func.t(ft, fa, fb);
324                         break;
325                 }
326         case D1S:{
327                         void *ft, *fa;
328 
329                         SPFROMREG(ft, NDS32Insn_OPCODE_Rt(insn));
330                         DPFROMREG(fa, NDS32Insn_OPCODE_Ra(insn));
331                         func.b(ft, fa);
332                         break;
333                 }
334         case CD:{
335                         unsigned int cmpop = NDS32Insn_OPCODE_BIT69(insn);
336                         void *ft, *fa, *fb;
337 
338                         SPFROMREG(ft, NDS32Insn_OPCODE_Rt(insn));
339                         DPFROMREG(fa, NDS32Insn_OPCODE_Ra(insn));
340                         DPFROMREG(fb, NDS32Insn_OPCODE_Rb(insn));
341                         if (cmpop < 0x8) {
342                                 cmpop = cmptab[cmpop];
343                                 fcmpd(ft, fa, fb, cmpop);
344                         } else
345                                 return SIGILL;
346                         break;
347                 }
348         default:
349                 return SIGILL;
350         }
351 
352         /*
353          * If an exception is required, generate a tidy SIGFPE exception.
354          */
355 #if IS_ENABLED(CONFIG_SUPPORT_DENORMAL_ARITHMETIC)
356         if (((fpu_reg->fpcsr << 5) & fpu_reg->fpcsr & FPCSR_mskALLE_NO_UDF_IEXE)
357             || ((fpu_reg->fpcsr << 5) & (fpu_reg->UDF_IEX_trap))) {
358 #else
359         if ((fpu_reg->fpcsr << 5) & fpu_reg->fpcsr & FPCSR_mskALLE) {
360 #endif
361                 return SIGFPE;
362         }
363         return 0;
364 }
365 
366 int do_fpuemu(struct pt_regs *regs, struct fpu_struct *fpu)
367 {
368         unsigned long insn = 0, addr = regs->ipc;
369         unsigned long emulpc, contpc;
370         unsigned char *pc = (void *)&insn;
371         char c;
372         int i = 0, ret;
373 
374         for (i = 0; i < 4; i++) {
375                 if (__get_user(c, (unsigned char *)addr++))
376                         return SIGBUS;
377                 *pc++ = c;
378         }
379 
380         insn = be32_to_cpu(insn);
381 
382         emulpc = regs->ipc;
383         contpc = regs->ipc + 4;
384 
385         if (NDS32Insn_OPCODE(insn) != cop0_op)
386                 return SIGILL;
387 
388         switch (NDS32Insn_OPCODE_COP0(insn)) {
389         case fs1_op:
390         case fs2_op:
391         case fd1_op:
392         case fd2_op:
393                 {
394                         /* a real fpu computation instruction */
395                         ret = fpu_emu(fpu, insn);
396                         if (!ret)
397                                 regs->ipc = contpc;
398                 }
399                 break;
400 
401         default:
402                 return SIGILL;
403         }
404 
405         return ret;
406 }
407 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp