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

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

Version: ~ [ linux-5.15-rc1 ] ~ [ linux-5.14.5 ] ~ [ linux-5.13.18 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.66 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.147 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.206 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.246 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.282 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.283 ] ~ [ 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 fsqrts_op:
117                                         func.b = fsqrts;
118                                         ftype = S1S;
119                                         break;
120                                 default:
121                                         return SIGILL;
122                                 }
123                                 break;
124                         default:
125                                 return SIGILL;
126                         }
127                         break;
128                 }
129         case fs2_op:
130                 switch (NDS32Insn_OPCODE_BIT69(insn)) {
131                 case fcmpeqs_op:
132                 case fcmpeqs_e_op:
133                 case fcmplts_op:
134                 case fcmplts_e_op:
135                 case fcmples_op:
136                 case fcmples_e_op:
137                 case fcmpuns_op:
138                 case fcmpuns_e_op:
139                         ftype = CS;
140                         break;
141                 default:
142                         return SIGILL;
143                 }
144                 break;
145         case fd1_op:{
146                         switch (NDS32Insn_OPCODE_BIT69(insn)) {
147                         case faddd_op:
148                                 func.t = faddd;
149                                 ftype = D2D;
150                                 break;
151                         case fsubd_op:
152                                 func.t = fsubd;
153                                 ftype = D2D;
154                                 break;
155                         case fmaddd_op:
156                                 func.t = fpemu_fmaddd;
157                                 ftype = D2D;
158                                 break;
159                         case fmsubd_op:
160                                 func.t = fpemu_fmsubd;
161                                 ftype = D2D;
162                                 break;
163                         case fnmaddd_op:
164                                 func.t = fpemu_fnmaddd;
165                                 ftype = D2D;
166                                 break;
167                         case fnmsubd_op:
168                                 func.t = fpemu_fnmsubd;
169                                 ftype = D2D;
170                                 break;
171                         case fmuld_op:
172                                 func.t = fmuld;
173                                 ftype = D2D;
174                                 break;
175                         case fdivd_op:
176                                 func.t = fdivd;
177                                 ftype = D2D;
178                                 break;
179                         case fd1_f2op_op:
180                                 switch (NDS32Insn_OPCODE_BIT1014(insn)) {
181                                 case fd2s_op:
182                                         func.b = fd2s;
183                                         ftype = D1S;
184                                         break;
185                                 case fsqrtd_op:
186                                         func.b = fsqrtd;
187                                         ftype = D1D;
188                                         break;
189                                 default:
190                                         return SIGILL;
191                                 }
192                                 break;
193                         default:
194                                 return SIGILL;
195 
196                         }
197                         break;
198                 }
199 
200         case fd2_op:
201                 switch (NDS32Insn_OPCODE_BIT69(insn)) {
202                 case fcmpeqd_op:
203                 case fcmpeqd_e_op:
204                 case fcmpltd_op:
205                 case fcmpltd_e_op:
206                 case fcmpled_op:
207                 case fcmpled_e_op:
208                 case fcmpund_op:
209                 case fcmpund_e_op:
210                         ftype = CD;
211                         break;
212                 default:
213                         return SIGILL;
214                 }
215                 break;
216 
217         default:
218                 return SIGILL;
219         }
220 
221         switch (ftype) {
222         case S1S:{
223                         void *ft, *fa;
224 
225                         SPFROMREG(ft, NDS32Insn_OPCODE_Rt(insn));
226                         SPFROMREG(fa, NDS32Insn_OPCODE_Ra(insn));
227                         func.b(ft, fa);
228                         break;
229                 }
230         case S2S:{
231                         void *ft, *fa, *fb;
232 
233                         SPFROMREG(ft, NDS32Insn_OPCODE_Rt(insn));
234                         SPFROMREG(fa, NDS32Insn_OPCODE_Ra(insn));
235                         SPFROMREG(fb, NDS32Insn_OPCODE_Rb(insn));
236                         func.t(ft, fa, fb);
237                         break;
238                 }
239         case S1D:{
240                         void *ft, *fa;
241 
242                         DPFROMREG(ft, NDS32Insn_OPCODE_Rt(insn));
243                         SPFROMREG(fa, NDS32Insn_OPCODE_Ra(insn));
244                         func.b(ft, fa);
245                         break;
246                 }
247         case CS:{
248                         unsigned int cmpop = NDS32Insn_OPCODE_BIT69(insn);
249                         void *ft, *fa, *fb;
250 
251                         SPFROMREG(ft, NDS32Insn_OPCODE_Rt(insn));
252                         SPFROMREG(fa, NDS32Insn_OPCODE_Ra(insn));
253                         SPFROMREG(fb, NDS32Insn_OPCODE_Rb(insn));
254                         if (cmpop < 0x8) {
255                                 cmpop = cmptab[cmpop];
256                                 fcmps(ft, fa, fb, cmpop);
257                         } else
258                                 return SIGILL;
259                         break;
260                 }
261         case D1D:{
262                         void *ft, *fa;
263 
264                         DPFROMREG(ft, NDS32Insn_OPCODE_Rt(insn));
265                         DPFROMREG(fa, NDS32Insn_OPCODE_Ra(insn));
266                         func.b(ft, fa);
267                         break;
268                 }
269         case D2D:{
270                         void *ft, *fa, *fb;
271 
272                         DPFROMREG(ft, NDS32Insn_OPCODE_Rt(insn));
273                         DPFROMREG(fa, NDS32Insn_OPCODE_Ra(insn));
274                         DPFROMREG(fb, NDS32Insn_OPCODE_Rb(insn));
275                         func.t(ft, fa, fb);
276                         break;
277                 }
278         case D1S:{
279                         void *ft, *fa;
280 
281                         SPFROMREG(ft, NDS32Insn_OPCODE_Rt(insn));
282                         DPFROMREG(fa, NDS32Insn_OPCODE_Ra(insn));
283                         func.b(ft, fa);
284                         break;
285                 }
286         case CD:{
287                         unsigned int cmpop = NDS32Insn_OPCODE_BIT69(insn);
288                         void *ft, *fa, *fb;
289 
290                         SPFROMREG(ft, NDS32Insn_OPCODE_Rt(insn));
291                         DPFROMREG(fa, NDS32Insn_OPCODE_Ra(insn));
292                         DPFROMREG(fb, NDS32Insn_OPCODE_Rb(insn));
293                         if (cmpop < 0x8) {
294                                 cmpop = cmptab[cmpop];
295                                 fcmpd(ft, fa, fb, cmpop);
296                         } else
297                                 return SIGILL;
298                         break;
299                 }
300         default:
301                 return SIGILL;
302         }
303 
304         /*
305          * If an exception is required, generate a tidy SIGFPE exception.
306          */
307 #if IS_ENABLED(CONFIG_SUPPORT_DENORMAL_ARITHMETIC)
308         if (((fpu_reg->fpcsr << 5) & fpu_reg->fpcsr & FPCSR_mskALLE_NO_UDFE) ||
309             ((fpu_reg->fpcsr & FPCSR_mskUDF) && (fpu_reg->UDF_trap)))
310 #else
311         if ((fpu_reg->fpcsr << 5) & fpu_reg->fpcsr & FPCSR_mskALLE)
312 #endif
313                 return SIGFPE;
314         return 0;
315 }
316 
317 
318 int do_fpuemu(struct pt_regs *regs, struct fpu_struct *fpu)
319 {
320         unsigned long insn = 0, addr = regs->ipc;
321         unsigned long emulpc, contpc;
322         unsigned char *pc = (void *)&insn;
323         char c;
324         int i = 0, ret;
325 
326         for (i = 0; i < 4; i++) {
327                 if (__get_user(c, (unsigned char *)addr++))
328                         return SIGBUS;
329                 *pc++ = c;
330         }
331 
332         insn = be32_to_cpu(insn);
333 
334         emulpc = regs->ipc;
335         contpc = regs->ipc + 4;
336 
337         if (NDS32Insn_OPCODE(insn) != cop0_op)
338                 return SIGILL;
339         switch (NDS32Insn_OPCODE_COP0(insn)) {
340         case fs1_op:
341         case fs2_op:
342         case fd1_op:
343         case fd2_op:
344                 {
345                         /* a real fpu computation instruction */
346                         ret = fpu_emu(fpu, insn);
347                         if (!ret)
348                                 regs->ipc = contpc;
349                 }
350                 break;
351 
352         default:
353                 return SIGILL;
354         }
355 
356         return ret;
357 }
358 

~ [ 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