The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/powerpc/booke/spe.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (C) 1996 Wolfgang Solfrank.
    3  * Copyright (C) 1996 TooLs GmbH.
    4  * All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  * 3. All advertising materials mentioning features or use of this software
   15  *    must display the following acknowledgement:
   16  *      This product includes software developed by TooLs GmbH.
   17  * 4. The name of TooLs GmbH may not be used to endorse or promote products
   18  *    derived from this software without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
   21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   23  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
   26  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   27  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
   28  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
   29  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   30  *
   31  *      $NetBSD: fpu.c,v 1.5 2001/07/22 11:29:46 wiz Exp $
   32  */
   33 
   34 #include <sys/cdefs.h>
   35 __FBSDID("$FreeBSD$");
   36 
   37 #include <sys/param.h>
   38 #include <sys/proc.h>
   39 #include <sys/systm.h>
   40 #include <sys/limits.h>
   41 
   42 #include <machine/altivec.h>
   43 #include <machine/fpu.h>
   44 #include <machine/ieeefp.h>
   45 #include <machine/pcb.h>
   46 #include <machine/psl.h>
   47 
   48 #include <powerpc/fpu/fpu_arith.h>
   49 #include <powerpc/fpu/fpu_emu.h>
   50 #include <powerpc/fpu/fpu_extern.h>
   51 
   52 void spe_handle_fpdata(struct trapframe *);
   53 void spe_handle_fpround(struct trapframe *);
   54 static int spe_emu_instr(uint32_t, struct fpemu *, struct fpn **, uint32_t *);
   55 
   56 static void
   57 save_vec_int(struct thread *td)
   58 {
   59         int     msr;
   60         struct  pcb *pcb;
   61 
   62         pcb = td->td_pcb;
   63 
   64         /*
   65          * Temporarily re-enable the vector unit during the save
   66          */
   67         msr = mfmsr();
   68         mtmsr(msr | PSL_VEC);
   69 
   70         /*
   71          * Save the vector registers and SPEFSCR to the PCB
   72          */
   73 #define EVSTDW(n)   __asm ("evstdw %1,0(%0)" \
   74                 :: "b"(pcb->pcb_vec.vr[n]), "n"(n));
   75         EVSTDW(0);      EVSTDW(1);      EVSTDW(2);      EVSTDW(3);
   76         EVSTDW(4);      EVSTDW(5);      EVSTDW(6);      EVSTDW(7);
   77         EVSTDW(8);      EVSTDW(9);      EVSTDW(10);     EVSTDW(11);
   78         EVSTDW(12);     EVSTDW(13);     EVSTDW(14);     EVSTDW(15);
   79         EVSTDW(16);     EVSTDW(17);     EVSTDW(18);     EVSTDW(19);
   80         EVSTDW(20);     EVSTDW(21);     EVSTDW(22);     EVSTDW(23);
   81         EVSTDW(24);     EVSTDW(25);     EVSTDW(26);     EVSTDW(27);
   82         EVSTDW(28);     EVSTDW(29);     EVSTDW(30);     EVSTDW(31);
   83 #undef EVSTDW
   84 
   85         __asm ( "evxor 0,0,0\n"
   86                 "evmwumiaa 0,0,0\n"
   87                 "evstdd 0,0(%0)" :: "b"(&pcb->pcb_vec.spare[0]));
   88         pcb->pcb_vec.vscr = mfspr(SPR_SPEFSCR);
   89 
   90         /*
   91          * Disable vector unit again
   92          */
   93         isync();
   94         mtmsr(msr);
   95 
   96 }
   97 
   98 void
   99 enable_vec(struct thread *td)
  100 {
  101         int     msr;
  102         struct  pcb *pcb;
  103         struct  trapframe *tf;
  104 
  105         pcb = td->td_pcb;
  106         tf = trapframe(td);
  107 
  108         /*
  109          * Save the thread's SPE CPU number, and set the CPU's current
  110          * vector thread
  111          */
  112         td->td_pcb->pcb_veccpu = PCPU_GET(cpuid);
  113         PCPU_SET(vecthread, td);
  114 
  115         /*
  116          * Enable the vector unit for when the thread returns from the
  117          * exception. If this is the first time the unit has been used by
  118          * the thread, initialise the vector registers and VSCR to 0, and
  119          * set the flag to indicate that the vector unit is in use.
  120          */
  121         tf->srr1 |= PSL_VEC;
  122         if (!(pcb->pcb_flags & PCB_VEC)) {
  123                 memset(&pcb->pcb_vec, 0, sizeof pcb->pcb_vec);
  124                 pcb->pcb_flags |= PCB_VEC;
  125                 pcb->pcb_vec.vscr = mfspr(SPR_SPEFSCR);
  126         }
  127 
  128         /*
  129          * Temporarily enable the vector unit so the registers
  130          * can be restored.
  131          */
  132         msr = mfmsr();
  133         mtmsr(msr | PSL_VEC);
  134 
  135         /* Restore SPEFSCR and ACC.  Use %r0 as the scratch for ACC. */
  136         mtspr(SPR_SPEFSCR, pcb->pcb_vec.vscr);
  137         __asm __volatile("isync;evldd 0, 0(%0); evmra 0,0\n"
  138             :: "b"(&pcb->pcb_vec.spare[0]));
  139 
  140         /* 
  141          * The lower half of each register will be restored on trap return.  Use
  142          * %r0 as a scratch register, and restore it last.
  143          */
  144 #define EVLDW(n)   __asm __volatile("evldw 0, 0(%0); evmergehilo "#n",0,"#n \
  145             :: "b"(&pcb->pcb_vec.vr[n]));
  146         EVLDW(1);       EVLDW(2);       EVLDW(3);       EVLDW(4);
  147         EVLDW(5);       EVLDW(6);       EVLDW(7);       EVLDW(8);
  148         EVLDW(9);       EVLDW(10);      EVLDW(11);      EVLDW(12);
  149         EVLDW(13);      EVLDW(14);      EVLDW(15);      EVLDW(16);
  150         EVLDW(17);      EVLDW(18);      EVLDW(19);      EVLDW(20);
  151         EVLDW(21);      EVLDW(22);      EVLDW(23);      EVLDW(24);
  152         EVLDW(25);      EVLDW(26);      EVLDW(27);      EVLDW(28);
  153         EVLDW(29);      EVLDW(30);      EVLDW(31);      EVLDW(0);
  154 #undef EVLDW
  155 
  156         isync();
  157         mtmsr(msr);
  158 }
  159 
  160 void
  161 save_vec(struct thread *td)
  162 {
  163         struct pcb *pcb;
  164 
  165         pcb = td->td_pcb;
  166 
  167         save_vec_int(td);
  168 
  169         /*
  170          * Clear the current vec thread and pcb's CPU id
  171          * XXX should this be left clear to allow lazy save/restore ?
  172          */
  173         pcb->pcb_veccpu = INT_MAX;
  174         PCPU_SET(vecthread, NULL);
  175 }
  176 
  177 /*
  178  * Save SPE state without dropping ownership.  This will only save state if
  179  * the current vector-thread is `td'.  This is used for taking core dumps, so
  180  * don't leak kernel information; overwrite the low words of each vector with
  181  * their real value, taken from the thread's trap frame, unconditionally.
  182  */
  183 void
  184 save_vec_nodrop(struct thread *td)
  185 {
  186         struct pcb *pcb;
  187         int i;
  188 
  189         if (td == PCPU_GET(vecthread))
  190                 save_vec_int(td);
  191 
  192         pcb = td->td_pcb;
  193 
  194         for (i = 0; i < 32; i++) {
  195                 pcb->pcb_vec.vr[i][1] =
  196                     td->td_frame ? td->td_frame->fixreg[i] : 0;
  197         }
  198 }
  199 
  200 #define SPE_INST_MASK   0x31f
  201 #define EADD    0x200
  202 #define ESUB    0x201
  203 #define EABS    0x204
  204 #define ENABS   0x205
  205 #define ENEG    0x206
  206 #define EMUL    0x208
  207 #define EDIV    0x209
  208 #define ECMPGT  0x20c
  209 #define ECMPLT  0x20d
  210 #define ECMPEQ  0x20e
  211 #define ECFUI   0x210
  212 #define ECFSI   0x211
  213 #define ECTUI   0x214
  214 #define ECTSI   0x215
  215 #define ECTUF   0x216
  216 #define ECTSF   0x217
  217 #define ECTUIZ  0x218
  218 #define ECTSIZ  0x21a
  219 
  220 #define SPE             0x4
  221 #define SPFP            0x6
  222 #define DPFP            0x7
  223 
  224 #define SPE_OPC         4
  225 #define OPC_SHIFT       26
  226 
  227 #define EVFSADD         0x280
  228 #define EVFSSUB         0x281
  229 #define EVFSABS         0x284
  230 #define EVFSNABS        0x285
  231 #define EVFSNEG         0x286
  232 #define EVFSMUL         0x288
  233 #define EVFSDIV         0x289
  234 #define EVFSCMPGT       0x28c
  235 #define EVFSCMPLT       0x28d
  236 #define EVFSCMPEQ       0x28e
  237 #define EVFSCFUI        0x290
  238 #define EVFSCFSI        0x291
  239 #define EVFSCTUI        0x294
  240 #define EVFSCTSI        0x295
  241 #define EVFSCTUF        0x296
  242 #define EVFSCTSF        0x297
  243 #define EVFSCTUIZ       0x298
  244 #define EVFSCTSIZ       0x29a
  245 
  246 #define EFSADD          0x2c0
  247 #define EFSSUB          0x2c1
  248 #define EFSABS          0x2c4
  249 #define EFSNABS         0x2c5
  250 #define EFSNEG          0x2c6
  251 #define EFSMUL          0x2c8
  252 #define EFSDIV          0x2c9
  253 #define EFSCMPGT        0x2cc
  254 #define EFSCMPLT        0x2cd
  255 #define EFSCMPEQ        0x2ce
  256 #define EFSCFD          0x2cf
  257 #define EFSCFUI         0x2d0
  258 #define EFSCFSI         0x2d1
  259 #define EFSCTUI         0x2d4
  260 #define EFSCTSI         0x2d5
  261 #define EFSCTUF         0x2d6
  262 #define EFSCTSF         0x2d7
  263 #define EFSCTUIZ        0x2d8
  264 #define EFSCTSIZ        0x2da
  265 
  266 #define EFDADD          0x2e0
  267 #define EFDSUB          0x2e1
  268 #define EFDABS          0x2e4
  269 #define EFDNABS         0x2e5
  270 #define EFDNEG          0x2e6
  271 #define EFDMUL          0x2e8
  272 #define EFDDIV          0x2e9
  273 #define EFDCMPGT        0x2ec
  274 #define EFDCMPLT        0x2ed
  275 #define EFDCMPEQ        0x2ee
  276 #define EFDCFS          0x2ef
  277 #define EFDCFUI         0x2f0
  278 #define EFDCFSI         0x2f1
  279 #define EFDCTUI         0x2f4
  280 #define EFDCTSI         0x2f5
  281 #define EFDCTUF         0x2f6
  282 #define EFDCTSF         0x2f7
  283 #define EFDCTUIZ        0x2f8
  284 #define EFDCTSIZ        0x2fa
  285 
  286 enum {
  287         NONE,
  288         SINGLE,
  289         DOUBLE,
  290         VECTOR,
  291 };
  292 
  293 static uint32_t fpscr_to_spefscr(uint32_t fpscr)
  294 {
  295         uint32_t spefscr;
  296 
  297         spefscr = 0;
  298 
  299         if (fpscr & FPSCR_VX)
  300                 spefscr |= SPEFSCR_FINV;
  301         if (fpscr & FPSCR_OX)
  302                 spefscr |= SPEFSCR_FOVF;
  303         if (fpscr & FPSCR_UX)
  304                 spefscr |= SPEFSCR_FUNF;
  305         if (fpscr & FPSCR_ZX)
  306                 spefscr |= SPEFSCR_FDBZ;
  307         if (fpscr & FPSCR_XX)
  308                 spefscr |= SPEFSCR_FX;
  309 
  310         return (spefscr);
  311 }
  312 
  313 /* Sign is 0 for unsigned, 1 for signed. */
  314 static int
  315 spe_to_int(struct fpemu *fpemu, struct fpn *fpn, uint32_t *val, int sign)
  316 {
  317         uint32_t res[2];
  318 
  319         res[0] = fpu_ftox(fpemu, fpn, res);
  320         if (res[0] != UINT_MAX && res[0] != 0)
  321                 fpemu->fe_cx |= FPSCR_OX;
  322         else if (sign == 0 && res[0] != 0)
  323                 fpemu->fe_cx |= FPSCR_UX;
  324         else
  325                 *val = res[1];
  326 
  327         return (0);
  328 }
  329 
  330 /* Masked instruction */
  331 /*
  332  * For compare instructions, returns 1 if success, 0 if not.  For all others,
  333  * returns -1, or -2 if no result needs recorded.
  334  */
  335 static int
  336 spe_emu_instr(uint32_t instr, struct fpemu *fpemu,
  337     struct fpn **result, uint32_t *iresult)
  338 {
  339         switch (instr & SPE_INST_MASK) {
  340         case EABS:
  341         case ENABS:
  342         case ENEG:
  343                 /* Taken care of elsewhere. */
  344                 break;
  345         case ECTUIZ:
  346                 fpemu->fe_cx &= ~FPSCR_RN;
  347                 fpemu->fe_cx |= FP_RZ;
  348         case ECTUI:
  349                 spe_to_int(fpemu, &fpemu->fe_f2, iresult, 0);
  350                 return (-1);
  351         case ECTSIZ:
  352                 fpemu->fe_cx &= ~FPSCR_RN;
  353                 fpemu->fe_cx |= FP_RZ;
  354         case ECTSI:
  355                 spe_to_int(fpemu, &fpemu->fe_f2, iresult, 1);
  356                 return (-1);
  357         case EADD:
  358                 *result = fpu_add(fpemu);
  359                 break;
  360         case ESUB:
  361                 *result = fpu_sub(fpemu);
  362                 break;
  363         case EMUL:
  364                 *result = fpu_mul(fpemu);
  365                 break;
  366         case EDIV:
  367                 *result = fpu_div(fpemu);
  368                 break;
  369         case ECMPGT:
  370                 fpu_compare(fpemu, 0);
  371                 if (fpemu->fe_cx & FPSCR_FG)
  372                         return (1);
  373                 return (0);
  374         case ECMPLT:
  375                 fpu_compare(fpemu, 0);
  376                 if (fpemu->fe_cx & FPSCR_FL)
  377                         return (1);
  378                 return (0);
  379         case ECMPEQ:
  380                 fpu_compare(fpemu, 0);
  381                 if (fpemu->fe_cx & FPSCR_FE)
  382                         return (1);
  383                 return (0);
  384         default:
  385                 printf("Unknown instruction %x\n", instr);
  386         }
  387 
  388         return (-1);
  389 }
  390 
  391 static int
  392 spe_explode(struct fpemu *fe, struct fpn *fp, uint32_t type,
  393     uint32_t hi, uint32_t lo)
  394 {
  395         uint32_t s;
  396 
  397         fp->fp_sign = hi >> 31;
  398         fp->fp_sticky = 0;
  399         switch (type) {
  400         case SINGLE:
  401                 s = fpu_stof(fp, hi);
  402                 break;
  403 
  404         case DOUBLE:
  405                 s = fpu_dtof(fp, hi, lo);
  406                 break;
  407         }
  408 
  409         if (s == FPC_QNAN && (fp->fp_mant[0] & FP_QUIETBIT) == 0) {
  410                 /*
  411                  * Input is a signalling NaN.  All operations that return
  412                  * an input NaN operand put it through a ``NaN conversion'',
  413                  * which basically just means ``turn on the quiet bit''.
  414                  * We do this here so that all NaNs internally look quiet
  415                  * (we can tell signalling ones by their class).
  416                  */
  417                 fp->fp_mant[0] |= FP_QUIETBIT;
  418                 fe->fe_cx = FPSCR_VXSNAN;       /* assert invalid operand */
  419                 s = FPC_SNAN;
  420         }
  421         fp->fp_class = s;
  422 
  423         return (0);
  424 }
  425 
  426 /*
  427  * Save the high word of a 64-bit GPR for manipulation in the exception handler.
  428  */
  429 static uint32_t
  430 spe_save_reg_high(int reg)
  431 {
  432         uint32_t vec[2];
  433 #define EVSTDW(n)   case n: __asm __volatile ("evstdw %1,0(%0)" \
  434                 :: "b"(vec), "n"(n) : "memory"); break;
  435         switch (reg) {
  436         EVSTDW(0);      EVSTDW(1);      EVSTDW(2);      EVSTDW(3);
  437         EVSTDW(4);      EVSTDW(5);      EVSTDW(6);      EVSTDW(7);
  438         EVSTDW(8);      EVSTDW(9);      EVSTDW(10);     EVSTDW(11);
  439         EVSTDW(12);     EVSTDW(13);     EVSTDW(14);     EVSTDW(15);
  440         EVSTDW(16);     EVSTDW(17);     EVSTDW(18);     EVSTDW(19);
  441         EVSTDW(20);     EVSTDW(21);     EVSTDW(22);     EVSTDW(23);
  442         EVSTDW(24);     EVSTDW(25);     EVSTDW(26);     EVSTDW(27);
  443         EVSTDW(28);     EVSTDW(29);     EVSTDW(30);     EVSTDW(31);
  444         }
  445 #undef EVSTDW
  446 
  447         return (vec[0]);
  448 }
  449 
  450 /*
  451  * Load the given value into the high word of the requested register.
  452  */
  453 static void
  454 spe_load_reg_high(int reg, uint32_t val)
  455 {
  456 #define EVLDW(n)   case n: __asm __volatile("evmergelo "#n",%0,"#n \
  457             :: "r"(val)); break;
  458         switch (reg) {
  459         EVLDW(1);       EVLDW(2);       EVLDW(3);       EVLDW(4);
  460         EVLDW(5);       EVLDW(6);       EVLDW(7);       EVLDW(8);
  461         EVLDW(9);       EVLDW(10);      EVLDW(11);      EVLDW(12);
  462         EVLDW(13);      EVLDW(14);      EVLDW(15);      EVLDW(16);
  463         EVLDW(17);      EVLDW(18);      EVLDW(19);      EVLDW(20);
  464         EVLDW(21);      EVLDW(22);      EVLDW(23);      EVLDW(24);
  465         EVLDW(25);      EVLDW(26);      EVLDW(27);      EVLDW(28);
  466         EVLDW(29);      EVLDW(30);      EVLDW(31);      EVLDW(0);
  467         }
  468 #undef EVLDW
  469 
  470 }
  471 
  472 void
  473 spe_handle_fpdata(struct trapframe *frame)
  474 {
  475         struct fpemu fpemu;
  476         struct fpn *result;
  477         uint32_t instr, instr_sec_op;
  478         uint32_t cr_shift, ra, rb, rd, src;
  479         uint32_t high, low, res, tmp; /* For vector operations. */
  480         uint32_t spefscr = 0;
  481         uint32_t ftod_res[2];
  482         int width; /* Single, Double, Vector, Integer */
  483         int err;
  484         uint32_t msr;
  485 
  486         err = fueword32((void *)frame->srr0, &instr);
  487 
  488         if (err != 0)
  489                 return;
  490                 /* Fault. */;
  491 
  492         if ((instr >> OPC_SHIFT) != SPE_OPC)
  493                 return;
  494 
  495         msr = mfmsr();
  496         /*
  497          * 'cr' field is the upper 3 bits of rd.  Magically, since a) rd is 5
  498          * bits, b) each 'cr' field is 4 bits, and c) Only the 'GT' bit is
  499          * modified for most compare operations, the full value of rd can be
  500          * used as a shift value.
  501          */
  502         rd = (instr >> 21) & 0x1f;
  503         ra = (instr >> 16) & 0x1f;
  504         rb = (instr >> 11) & 0x1f;
  505         src = (instr >> 5) & 0x7;
  506         cr_shift = 28 - (rd & 0x1f);
  507 
  508         instr_sec_op = (instr & 0x7ff);
  509 
  510         memset(&fpemu, 0, sizeof(fpemu));
  511 
  512         width = NONE;
  513         switch (src) {
  514         case SPE:
  515                 mtmsr(msr | PSL_VEC);
  516                 switch (instr_sec_op) {
  517                 case EVFSABS:
  518                         high = spe_save_reg_high(ra) & ~(1U << 31);
  519                         frame->fixreg[rd] = frame->fixreg[ra] & ~(1U << 31);
  520                         spe_load_reg_high(rd, high);
  521                         break;
  522                 case EVFSNABS:
  523                         high = spe_save_reg_high(ra) | (1U << 31);
  524                         frame->fixreg[rd] = frame->fixreg[ra] | (1U << 31);
  525                         spe_load_reg_high(rd, high);
  526                         break;
  527                 case EVFSNEG:
  528                         high = spe_save_reg_high(ra) ^ (1U << 31);
  529                         frame->fixreg[rd] = frame->fixreg[ra] ^ (1U << 31);
  530                         spe_load_reg_high(rd, high);
  531                         break;
  532                 default:
  533                         /* High word */
  534                         spe_explode(&fpemu, &fpemu.fe_f1, SINGLE,
  535                             spe_save_reg_high(ra), 0);
  536                         spe_explode(&fpemu, &fpemu.fe_f2, SINGLE,
  537                             spe_save_reg_high(rb), 0);
  538                         high = spe_emu_instr(instr_sec_op, &fpemu, &result,
  539                             &tmp);
  540 
  541                         if (high < 0)
  542                                 spe_load_reg_high(rd, tmp);
  543 
  544                         spefscr = fpscr_to_spefscr(fpemu.fe_cx) << 16;
  545                         /* Clear the fpemu to start over on the lower bits. */
  546                         memset(&fpemu, 0, sizeof(fpemu));
  547 
  548                         /* Now low word */
  549                         spe_explode(&fpemu, &fpemu.fe_f1, SINGLE,
  550                             frame->fixreg[ra], 0);
  551                         spe_explode(&fpemu, &fpemu.fe_f2, SINGLE,
  552                             frame->fixreg[rb], 0);
  553                         spefscr |= fpscr_to_spefscr(fpemu.fe_cx);
  554                         low = spe_emu_instr(instr_sec_op, &fpemu, &result,
  555                             &frame->fixreg[rd]);
  556                         if (instr_sec_op == EVFSCMPEQ ||
  557                             instr_sec_op == EVFSCMPGT ||
  558                             instr_sec_op == EVFSCMPLT) {
  559                                 res = (high << 3) | (low << 2) |
  560                                     ((high | low) << 1) | (high & low);
  561                                 width = NONE;
  562                         } else
  563                                 width = VECTOR;
  564                         break;
  565                 }
  566                 goto end;
  567 
  568         case SPFP:
  569                 switch (instr_sec_op) {
  570                 case EFSABS:
  571                         frame->fixreg[rd] = frame->fixreg[ra] & ~(1U << 31);
  572                         break;
  573                 case EFSNABS:
  574                         frame->fixreg[rd] = frame->fixreg[ra] | (1U << 31);
  575                         break;
  576                 case EFSNEG:
  577                         frame->fixreg[rd] = frame->fixreg[ra] ^ (1U << 31);
  578                         break;
  579                 case EFSCFD:
  580                         mtmsr(msr | PSL_VEC);
  581                         spe_explode(&fpemu, &fpemu.fe_f3, DOUBLE,
  582                             spe_save_reg_high(rb), frame->fixreg[rb]);
  583                         result = &fpemu.fe_f3;
  584                         width = SINGLE;
  585                         break;
  586                 default:
  587                         spe_explode(&fpemu, &fpemu.fe_f1, SINGLE,
  588                             frame->fixreg[ra], 0);
  589                         spe_explode(&fpemu, &fpemu.fe_f2, SINGLE,
  590                             frame->fixreg[rb], 0);
  591                         width = SINGLE;
  592                 }
  593                 break;
  594         case DPFP:
  595                 mtmsr(msr | PSL_VEC);
  596                 switch (instr_sec_op) {
  597                 case EFDABS:
  598                         high = spe_save_reg_high(ra) & ~(1U << 31);
  599                         frame->fixreg[rd] = frame->fixreg[ra];
  600                         spe_load_reg_high(rd, high);
  601                         break;
  602                 case EFDNABS:
  603                         high = spe_save_reg_high(ra) | (1U << 31);
  604                         frame->fixreg[rd] = frame->fixreg[ra];
  605                         spe_load_reg_high(rd, high);
  606                         break;
  607                 case EFDNEG:
  608                         high = spe_save_reg_high(ra) ^ (1U << 31);
  609                         frame->fixreg[rd] = frame->fixreg[ra];
  610                         spe_load_reg_high(rd, high);
  611                         break;
  612                 case EFDCFS:
  613                         spe_explode(&fpemu, &fpemu.fe_f3, SINGLE,
  614                             frame->fixreg[rb], 0);
  615                         result = &fpemu.fe_f3;
  616                         width = DOUBLE;
  617                         break;
  618                 default:
  619                         spe_explode(&fpemu, &fpemu.fe_f1, DOUBLE,
  620                             spe_save_reg_high(ra), frame->fixreg[ra]);
  621                         spe_explode(&fpemu, &fpemu.fe_f2, DOUBLE,
  622                             spe_save_reg_high(rb), frame->fixreg[rb]);
  623                         width = DOUBLE;
  624                 }
  625                 break;
  626         }
  627         switch (instr_sec_op) {
  628         case EFDCFS:
  629         case EFSCFD:
  630                 /* Already handled. */
  631                 break;
  632         default:
  633                 res = spe_emu_instr(instr_sec_op, &fpemu, &result,
  634                     &frame->fixreg[rd]);
  635                 if (res != -1)
  636                         res <<= 2;
  637                 break;
  638         }
  639 
  640         switch (instr_sec_op & SPE_INST_MASK) {
  641         case ECMPEQ:
  642         case ECMPGT:
  643         case ECMPLT:
  644                 frame->cr &= ~(0xf << cr_shift);
  645                 frame->cr |= (res << cr_shift);
  646                 break;
  647         case ECTUI:
  648         case ECTUIZ:
  649         case ECTSI:
  650         case ECTSIZ:
  651                 break;
  652         default:
  653                 switch (width) {
  654                 case NONE:
  655                 case VECTOR:
  656                         break;
  657                 case SINGLE:
  658                         frame->fixreg[rd] = fpu_ftos(&fpemu, result);
  659                         break;
  660                 case DOUBLE:
  661                         spe_load_reg_high(rd, fpu_ftod(&fpemu, result, ftod_res));
  662                         frame->fixreg[rd] = ftod_res[1];
  663                         break;
  664                 default:
  665                         panic("Unknown storage width %d", width);
  666                         break;
  667                 }
  668         }
  669 
  670 end:
  671         spefscr |= (mfspr(SPR_SPEFSCR) & ~SPEFSCR_FINVS);
  672         mtspr(SPR_SPEFSCR, spefscr);
  673         frame->srr0 += 4;
  674         mtmsr(msr);
  675 
  676         return;
  677 }
  678 
  679 void
  680 spe_handle_fpround(struct trapframe *frame)
  681 {
  682 
  683         /*
  684          * Punt fpround exceptions for now.  This leaves the truncated result in
  685          * the register.  We'll deal with overflow/underflow later.
  686          */
  687         return;
  688 }

Cache object: e63809ceef313341adb4d175b084a247


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.