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/bitsy/fpiarm.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  * this doesn't attempt to implement ARM floating-point properties
    3  * that aren't visible in the Inferno environment.
    4  * all arithmetic is done in double precision.
    5  * the FP trap status isn't updated.
    6  */
    7 #include        <u.h>
    8 #include        "../port/lib.h"
    9 #include        "mem.h"
   10 #include        "dat.h"
   11 #include        "fns.h"
   12 #include        "io.h"
   13 
   14 #include        <ureg.h>
   15 
   16 #include "fpi.h"
   17 
   18 /* undef this if correct kernel r13 isn't in Ureg;
   19  * check calculation in fpiarm below
   20  */
   21 
   22 
   23 #define REG(ur, x) (*(long*)(((char*)(ur))+roff[(x)]))
   24 #define FR(ufp, x) (*(Internal*)(ufp)->regs[(x)&7])
   25 
   26 typedef struct FP2 FP2;
   27 typedef struct FP1 FP1;
   28 
   29 struct FP2 {
   30         char*   name;
   31         void    (*f)(Internal, Internal, Internal*);
   32 };
   33 
   34 struct FP1 {
   35         char*   name;
   36         void    (*f)(Internal*, Internal*);
   37 };
   38 
   39 enum {
   40         N = 1<<31,
   41         Z = 1<<30,
   42         C = 1<<29,
   43         V = 1<<28,
   44         REGPC = 15,
   45 };
   46 
   47 int     fpemudebug = 0;
   48 
   49 #undef OFR
   50 #define OFR(X)  ((ulong)&((Ureg*)0)->X)
   51 
   52 static  int     roff[] = {
   53         OFR(r0), OFR(r1), OFR(r2), OFR(r3),
   54         OFR(r4), OFR(r5), OFR(r6), OFR(r7),
   55         OFR(r8), OFR(r9), OFR(r10), OFR(r11),
   56         OFR(r12), OFR(r13), OFR(r14), OFR(pc),
   57 };
   58 
   59 static Internal fpconst[8] = {  /* indexed by op&7 */
   60         /* s, e, l, h */
   61         {0, 0x1, 0x00000000, 0x00000000}, /* 0.0 */
   62         {0, 0x3FF, 0x00000000, 0x08000000},     /* 1.0 */
   63         {0, 0x400, 0x00000000, 0x08000000},     /* 2.0 */
   64         {0, 0x400, 0x00000000, 0x0C000000},     /* 3.0 */
   65         {0, 0x401, 0x00000000, 0x08000000},     /* 4.0 */
   66         {0, 0x401, 0x00000000, 0x0A000000},     /* 5.0 */
   67         {0, 0x3FE, 0x00000000, 0x08000000},     /* 0.5 */
   68         {0, 0x402, 0x00000000, 0x0A000000},     /* 10.0 */
   69 };
   70 
   71 /*
   72  * arm binary operations
   73  */
   74 
   75 static void
   76 fadd(Internal m, Internal n, Internal *d)
   77 {
   78         (m.s == n.s? fpiadd: fpisub)(&m, &n, d);
   79 }
   80 
   81 static void
   82 fsub(Internal m, Internal n, Internal *d)
   83 {
   84         m.s ^= 1;
   85         (m.s == n.s? fpiadd: fpisub)(&m, &n, d);
   86 }
   87 
   88 static void
   89 fsubr(Internal m, Internal n, Internal *d)
   90 {
   91         n.s ^= 1;
   92         (n.s == m.s? fpiadd: fpisub)(&n, &m, d);
   93 }
   94 
   95 static void
   96 fmul(Internal m, Internal n, Internal *d)
   97 {
   98         fpimul(&m, &n, d);
   99 }
  100 
  101 static void
  102 fdiv(Internal m, Internal n, Internal *d)
  103 {
  104         fpidiv(&m, &n, d);
  105 }
  106 
  107 static void
  108 fdivr(Internal m, Internal n, Internal *d)
  109 {
  110         fpidiv(&n, &m, d);
  111 }
  112 
  113 /*
  114  * arm unary operations
  115  */
  116 
  117 static void
  118 fmov(Internal *m, Internal *d)
  119 {
  120         *d = *m;
  121 }
  122 
  123 static void
  124 fmovn(Internal *m, Internal *d)
  125 {
  126         *d = *m;
  127         d->s ^= 1;
  128 }
  129 
  130 static void
  131 fabsf(Internal *m, Internal *d)
  132 {
  133         *d = *m;
  134         d->s = 0;
  135 }
  136 
  137 static void
  138 frnd(Internal *m, Internal *d)
  139 {
  140         short e;
  141 
  142         (m->s? fsub: fadd)(fpconst[6], *m, d);
  143         if(IsWeird(d))
  144                 return;
  145         fpiround(d);
  146         e = (d->e - ExpBias) + 1;
  147         if(e <= 0)
  148                 SetZero(d);
  149         else if(e > FractBits){
  150                 if(e < 2*FractBits)
  151                         d->l &= ~((1<<(2*FractBits - e))-1);
  152         }else{
  153                 d->l = 0;
  154                 if(e < FractBits)
  155                         d->h &= ~((1<<(FractBits-e))-1);
  156         }
  157 }
  158 
  159 static  FP1     optab1[16] = {  /* Fd := OP Fm */
  160 [0]     {"MOVF",        fmov},
  161 [1]     {"NEGF",        fmovn},
  162 [2]     {"ABSF",        fabsf},
  163 [3]     {"RNDF",        frnd},
  164 [4]     {"SQTF",        /*fsqt*/0},
  165 /* LOG, LGN, EXP, SIN, COS, TAN, ASN, ACS, ATN all `deprecated' */
  166 /* URD and NRM aren't implemented */
  167 };
  168 
  169 static  FP2     optab2[16] = {  /* Fd := Fn OP Fm */
  170 [0]     {"ADDF",        fadd},
  171 [1]     {"MULF",        fmul},
  172 [2]     {"SUBF",        fsub},
  173 [3]     {"RSUBF",       fsubr},
  174 [4]     {"DIVF",        fdiv},
  175 [5]     {"RDIVF",       fdivr},
  176 /* POW, RPW deprecated */
  177 [8]     {"REMF",        /*frem*/0},
  178 [9]     {"FMF", fmul},  /* fast multiply */
  179 [10]    {"FDV", fdiv},  /* fast divide */
  180 [11]    {"FRD", fdivr}, /* fast reverse divide */
  181 /* POL deprecated */
  182 };
  183 
  184 static ulong
  185 fcmp(Internal *n, Internal *m)
  186 {
  187         int i;
  188         Internal rm, rn;
  189 
  190         if(IsWeird(m) || IsWeird(n)){
  191                 /* BUG: should trap if not masked */
  192                 return V|C;
  193         }
  194         rn = *n;
  195         rm = *m;
  196         fpiround(&rn);
  197         fpiround(&rm);
  198         i = fpicmp(&rn, &rm);
  199         if(i > 0)
  200                 return C;
  201         else if(i == 0)
  202                 return C|Z;
  203         else
  204                 return N;
  205 }
  206 
  207 static void
  208 fld(void (*f)(Internal*, void*), int d, ulong ea, int n, FPsave *ufp)
  209 {
  210         void *mem;
  211 
  212         mem = (void*)ea;
  213         (*f)(&FR(ufp, d), mem);
  214         if(fpemudebug)
  215                 print("MOV%c #%lux, F%d\n", n==8? 'D': 'F', ea, d);
  216 }
  217 
  218 static void
  219 fst(void (*f)(void*, Internal*), ulong ea, int s, int n, FPsave *ufp)
  220 {
  221         Internal tmp;
  222         void *mem;
  223 
  224         mem = (void*)ea;
  225         tmp = FR(ufp, s);
  226         if(fpemudebug)
  227                 print("MOV%c    F%d,#%lux\n", n==8? 'D': 'F', s, ea);
  228         (*f)(mem, &tmp);
  229 }
  230 
  231 static int
  232 condok(int cc, int c)
  233 {
  234         switch(c){
  235         case 0: /* Z set */
  236                 return cc&Z;
  237         case 1: /* Z clear */
  238                 return (cc&Z) == 0;
  239         case 2: /* C set */
  240                 return cc&C;
  241         case 3: /* C clear */
  242                 return (cc&C) == 0;
  243         case 4: /* N set */
  244                 return cc&N;
  245         case 5: /* N clear */
  246                 return (cc&N) == 0;
  247         case 6: /* V set */
  248                 return cc&V;
  249         case 7: /* V clear */
  250                 return (cc&V) == 0;
  251         case 8: /* C set and Z clear */
  252                 return cc&C && (cc&Z) == 0;
  253         case 9: /* C clear or Z set */
  254                 return (cc&C) == 0 || cc&Z;
  255         case 10:        /* N set and V set, or N clear and V clear */
  256                 return (~cc&(N|V))==0 || (cc&(N|V)) == 0;
  257         case 11:        /* N set and V clear, or N clear and V set */
  258                 return (cc&(N|V))==N || (cc&(N|V))==V;
  259         case 12:        /* Z clear, and either N set and V set or N clear and V clear */
  260                 return (cc&Z) == 0 && ((~cc&(N|V))==0 || (cc&(N|V))==0);
  261         case 13:        /* Z set, or N set and V clear or N clear and V set */
  262                 return (cc&Z) || (cc&(N|V))==N || (cc&(N|V))==V;
  263         case 14:        /* always */
  264                 return 1;
  265         case 15:        /* never (reserved) */
  266                 return 0;
  267         }
  268         return 0;       /* not reached */
  269 }
  270 
  271 static void
  272 unimp(ulong pc, ulong op)
  273 {
  274         char buf[60];
  275 
  276         snprint(buf, sizeof(buf), "sys: fp: pc=%lux unimp fp 0x%.8lux", pc, op);
  277         if(fpemudebug)
  278                 print("FPE: %s\n", buf);
  279         error(buf);
  280         /* no return */
  281 }
  282 
  283 static void
  284 fpemu(ulong pc, ulong op, Ureg *ur, FPsave *ufp)
  285 {
  286         int rn, rd, tag, o;
  287         long off;
  288         ulong ea;
  289         Internal tmp, *fm, *fn;
  290 
  291         /* note: would update fault status here if we noted numeric exceptions */
  292 
  293         /*
  294          * LDF, STF; 10.1.1
  295          */
  296         if(((op>>25)&7) == 6){
  297                 if(op & (1<<22))
  298                         unimp(pc, op);  /* packed or extended */
  299                 rn = (op>>16)&0xF;
  300                 off = (op&0xFF)<<2;
  301                 if((op & (1<<23)) == 0)
  302                         off = -off;
  303                 ea = REG(ur, rn);
  304                 if(rn == REGPC)
  305                         ea += 8;
  306                 if(op & (1<<24))
  307                         ea += off;
  308                 rd = (op>>12)&7;
  309                 if(op & (1<<20)){
  310                         if(op & (1<<15))
  311                                 fld(fpid2i, rd, ea, 8, ufp);
  312                         else
  313                                 fld(fpis2i, rd, ea, 4, ufp);
  314                 }else{
  315                         if(op & (1<<15))
  316                                 fst(fpii2d, ea, rd, 8, ufp);
  317                         else
  318                                 fst(fpii2s, ea, rd, 4, ufp);
  319                 }
  320                 if((op & (1<<24)) == 0)
  321                         ea += off;
  322                 if(op & (1<<21))
  323                         REG(ur, rn) = ea;
  324                 return;
  325         }
  326 
  327         /*
  328          * CPRT/transfer, 10.3
  329          */
  330         if(op & (1<<4)){
  331                 rd = (op>>12) & 0xF;
  332 
  333                 /*
  334                  * compare, 10.3.1
  335                  */
  336                 if(rd == 15 && op & (1<<20)){
  337                         rn = (op>>16)&7;
  338                         fn = &FR(ufp, rn);
  339                         if(op & (1<<3)){
  340                                 fm = &fpconst[op&7];
  341                                 tag = 'C';
  342                         }else{
  343                                 fm = &FR(ufp, op&7);
  344                                 tag = 'F';
  345                         }
  346                         switch((op>>21)&7){
  347                         default:
  348                                 unimp(pc, op);
  349                         case 4: /* CMF: Fn :: Fm */
  350                         case 6: /* CMFE: Fn :: Fm (with exception) */
  351                                 ur->psr &= ~(N|C|Z|V);
  352                                 ur->psr |= fcmp(fn, fm);
  353                                 break;
  354                         case 5: /* CNF: Fn :: -Fm */
  355                         case 7: /* CNFE: Fn :: -Fm (with exception) */
  356                                 tmp = *fm;
  357                                 tmp.s ^= 1;
  358                                 ur->psr &= ~(N|C|Z|V);
  359                                 ur->psr |= fcmp(fn, &tmp);
  360                                 break;
  361                         }
  362                         if(fpemudebug)
  363                                 print("CMPF     %c%d,F%ld =%lux\n", tag, rn, op&7, ur->psr>>28);
  364                         return;
  365                 }
  366 
  367                 /*
  368                  * other transfer, 10.3
  369                  */
  370                 switch((op>>20)&0xF){
  371                 default:
  372                         unimp(pc, op);
  373                 case 0: /* FLT */
  374                         rn = (op>>16) & 7;
  375                         fpiw2i(&FR(ufp, rn), &REG(ur, rd));
  376                         if(fpemudebug)
  377                                 print("MOVW[FD] R%d, F%d\n", rd, rn);
  378                         break;
  379                 case 1: /* FIX */
  380                         if(op & (1<<3))
  381                                 unimp(pc, op);
  382                         rn = op & 7;
  383                         tmp = FR(ufp, rn);
  384                         fpii2w(&REG(ur, rd), &tmp);
  385                         if(fpemudebug)
  386                                 print("MOV[FD]W F%d, R%d =%ld\n", rn, rd, REG(ur, rd));
  387                         break;
  388                 case 2: /* FPSR := Rd */
  389                         ufp->status = REG(ur, rd);
  390                         if(fpemudebug)
  391                                 print("MOVW     R%d, FPSR\n", rd);
  392                         break;
  393                 case 3: /* Rd := FPSR */
  394                         REG(ur, rd) = ufp->status;
  395                         if(fpemudebug)
  396                                 print("MOVW     FPSR, R%d\n", rd);
  397                         break;
  398                 case 4: /* FPCR := Rd */
  399                         ufp->control = REG(ur, rd);
  400                         if(fpemudebug)
  401                                 print("MOVW     R%d, FPCR\n", rd);
  402                         break;
  403                 case 5: /* Rd := FPCR */
  404                         REG(ur, rd) = ufp->control;
  405                         if(fpemudebug)
  406                                 print("MOVW     FPCR, R%d\n", rd);
  407                         break;
  408                 }
  409                 return;
  410         }
  411 
  412         /*
  413          * arithmetic
  414          */
  415 
  416         if(op & (1<<3)){        /* constant */
  417                 fm = &fpconst[op&7];
  418                 tag = 'C';
  419         }else{
  420                 fm = &FR(ufp, op&7);
  421                 tag = 'F';
  422         }
  423         rd = (op>>12)&7;
  424         o = (op>>20)&0xF;
  425         if(op & (1<<15)){       /* monadic */
  426                 FP1 *fp;
  427                 fp = &optab1[o];
  428                 if(fp->f == nil)
  429                         unimp(pc, op);
  430                 if(fpemudebug)
  431                         print("%s       %c%ld,F%d\n", fp->name, tag, op&7, rd);
  432                 (*fp->f)(fm, &FR(ufp, rd));
  433         } else {
  434                 FP2 *fp;
  435                 fp = &optab2[o];
  436                 if(fp->f == nil)
  437                         unimp(pc, op);
  438                 rn = (op>>16)&7;
  439                 if(fpemudebug)
  440                         print("%s       %c%ld,F%d,F%d\n", fp->name, tag, op&7, rn, rd);
  441                 (*fp->f)(*fm, FR(ufp, rn), &FR(ufp, rd));
  442         }
  443 }
  444 
  445 void
  446 casemu(ulong pc, ulong op, Ureg *ur)
  447 {
  448         ulong *rp, ro, rn, *rd;
  449 
  450         USED(pc);
  451 
  452         rp = (ulong*)ur;
  453         ro = rp[op>>16 & 0x7];
  454         rn = rp[op>>0 & 0x7];
  455         rd = rp + (op>>12 & 0x7);
  456         rp = (ulong*)*rd;
  457         validaddr((ulong)rp, 4, 1);
  458         splhi();
  459         if(*rd = (*rp == ro))
  460                 *rp = rn;
  461         spllo();
  462 }
  463 
  464 int ldrexvalid;
  465 
  466 void
  467 ldrex(ulong pc, ulong op, Ureg *ur)
  468 {
  469         ulong *rp, *rd, *addr;
  470 
  471         USED(pc);
  472 
  473         rp = (ulong*)ur;
  474         rd = rp + (op>>16 & 0x7);
  475         addr = (ulong*)*rd;
  476         validaddr((ulong)addr, 4, 0);
  477         ldrexvalid = 1;
  478         rp[op>>12 & 0x7] = *addr;
  479         if(fpemudebug)
  480                 print("ldrex, r%ld = [r%ld]@0x%8.8p = 0x%8.8lux",
  481                         op>>12 & 0x7, op>>16 & 0x7, addr, rp[op>>12 & 0x7]);
  482 }
  483 
  484 void
  485 strex(ulong pc, ulong op, Ureg *ur)
  486 {
  487         ulong *rp, rn, *rd, *addr;
  488 
  489         USED(pc);
  490 
  491         rp = (ulong*)ur;
  492         rd = rp + (op>>16 & 0x7);
  493         rn = rp[op>>0 & 0x7];
  494         addr = (ulong*)*rd;
  495         validaddr((ulong)addr, 4, 1);
  496         splhi();
  497         if(ldrexvalid){
  498                 if(fpemudebug)
  499                         print("strex valid, [r%ld]@0x%8.8p = r%ld = 0x%8.8lux",
  500                                 op>>16 & 0x7, addr, op>>0 & 0x7, rn);
  501                 *addr = rn;
  502                 ldrexvalid = 0;
  503                 rp[op>>12 & 0x7] = 0;
  504         }else{
  505                 if(fpemudebug)
  506                         print("strex invalid, r%ld = 1", op>>16 & 0x7);
  507                 rp[op>>12 & 0x7] = 1;
  508         }
  509         spllo();
  510 }
  511 
  512 struct {
  513         ulong   opc;
  514         ulong   mask;
  515         void    (*f)(ulong, ulong, Ureg*);
  516 } specialopc[] = {
  517         { 0x01900f9f, 0x0ff00fff, ldrex },
  518         { 0x01800f90, 0x0ff00ff0, strex },
  519         { 0x0ed00100, 0x0ef08100, casemu },
  520         { 0x00000000, 0x00000000, nil }
  521 };
  522 
  523 
  524 /*
  525  * returns the number of FP instructions emulated
  526  */
  527 int
  528 fpiarm(Ureg *ur)
  529 {
  530         ulong op, o;
  531         FPsave *ufp;
  532         int i, n;
  533 
  534         if (up == nil)
  535                 panic("fpiarm not in a process");
  536         ufp = &up->fpsave;
  537                 /* because all the state is in the proc structure,
  538                  * it need not be saved/restored
  539                  */
  540         if(up->fpstate != FPactive) {
  541 //              assert(sizeof(Internal) == sizeof(ufp->regs[0]));
  542                 up->fpstate = FPactive;
  543                 ufp->control = 0;
  544                 ufp->status = (0x01<<28)|(1<<12);       /* software emulation, alternative C flag */
  545                 for(n = 0; n < 8; n++)
  546                         FR(ufp, n) = fpconst[0];
  547         }
  548         for(n=0; ;n++){
  549                 if(fpemudebug)
  550                         print("0x%8.8lux ", ur->pc);
  551                 validaddr(ur->pc, 4, 0);
  552                 op = *(ulong*)(ur->pc);
  553                 o = (op>>24) & 0xF;
  554                 if(condok(ur->psr, op>>28)){
  555                         for(i = 0; specialopc[i].f; i++)
  556                                 if((op & specialopc[i].mask) == specialopc[i].opc)
  557                                         break;
  558                         if(specialopc[i].f)
  559                                 specialopc[i].f(ur->pc, op, ur);
  560                         else if((op & 0xF00) != 0x100 || o != 0xE && (o&~1) != 0xC)
  561                                 break;
  562                         else
  563                                 fpemu(ur->pc, op, ur, ufp);
  564                 }else if((op & 0xF00) != 0x100 || o != 0xE && (o&~1) != 0xC)
  565                         break;
  566                 ur->pc += 4;
  567         }
  568         if(fpemudebug) print("\n");
  569         return n;
  570 }

Cache object: 34b71be075204a4adf07e757e42537e1


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