]> git.lizzy.rs Git - plan9front.git/commitdiff
ARM: kernel: add vfp emulator to bcm, teg2, omap, kw
authorjpathy <jpathy@mail.nanosouffle.net>
Tue, 11 Jun 2013 19:41:41 +0000 (01:11 +0530)
committerjpathy <jpathy@mail.nanosouffle.net>
Tue, 11 Jun 2013 19:41:41 +0000 (01:11 +0530)
sys/src/9/bcm/fpiarm.c
sys/src/9/kw/arm.h
sys/src/9/kw/dat.h
sys/src/9/kw/fpiarm.c
sys/src/9/omap/arm.h
sys/src/9/omap/dat.h
sys/src/9/omap/fpiarm.c
sys/src/9/teg2/fpiarm.c

index 571e89fa6c3a7296146a655efdec209bead651b0..d92455328e0ee8999f52126832d104f709f4f546 100644 (file)
 #include       "arm.h"
 #include       "fpi.h"
 
-#define ARM7500                        /* emulate old pre-VFP opcodes */
-
 /* undef this if correct kernel r13 isn't in Ureg;
  * check calculation in fpiarm below
  */
-
 #define        REG(ur, x) (*(long*)(((char*)(ur))+roff[(x)]))
-#ifdef ARM7500
-#define        FR(ufp, x) (*(Internal*)(ufp)->regs[(x)&7])
-#else
-#define        FR(ufp, x) (*(Internal*)(ufp)->regs[(x)&(Nfpregs - 1)])
-#endif
+#define        FR(ufp, x) (*(Internal*)(ufp)->regs[(x)&(Nfpctlregs - 1)])
 
 typedef struct FP2 FP2;
 typedef struct FP1 FP1;
@@ -192,6 +185,24 @@ static     FP2     optab2[16] = {  /* Fd := Fn OP Fm */
 /* POL deprecated */
 };
 
+/*
+ * ARM VFP opcodes
+ */
+
+static FP1     voptab1[32] = { /* Vd := OP Vm */
+[0]    {"MOVF",        fmov},
+[1]    {"ABSF",        fabsf},
+[2]    {"NEGF",        fmovn},
+[15]   {"CVTF",        fmov},
+};
+
+static FP2     voptab2[16] = { /* Vd := Vn FOP Fm */
+[4]    {"MULF",        fmul},
+[6]    {"ADDF",        fadd},
+[7]    {"SUBF",        fsub},
+[8]    {"DIVF",        fdiv},
+};
+
 static ulong
 fcmp(Internal *n, Internal *m)
 {
@@ -292,7 +303,7 @@ unimp(ulong pc, ulong op)
 }
 
 static void
-fpemu(ulong pc, ulong op, Ureg *ur, FPsave *ufp)
+fpaemu(ulong pc, ulong op, Ureg *ur, FPsave *ufp)
 {
        int rn, rd, tag, o;
        long off;
@@ -458,6 +469,174 @@ fpemu(ulong pc, ulong op, Ureg *ur, FPsave *ufp)
        }
 }
 
+static void
+vfpoptoi(Internal *fm, uchar o2, uchar o4)
+{
+       fm->s = o2>>3;
+       fm->e = ((o2>>3) | ~(o2 & 4)) - 3 + ExpBias;
+       fm->l = 0;
+       fm->h = o4 << (20+NGuardBits);
+       if(fm->e)
+               fm->h |= HiddenBit;
+       else
+               fm->e++;
+}
+
+static void
+vfpemu(ulong pc, ulong op, Ureg *ur, FPsave *ufp)
+{
+       int sz, vd, o1, o2, o3, o4, o, tag;
+       long off;
+       ulong ea;
+       Word w;
+       
+       Internal *fm, fc;
+
+       /* note: would update fault status here if we noted numeric exceptions */
+
+       sz = op & (1<<8);
+       o1 = (op>>20) & 0xF;
+       o2 = (op>>16) & 0xF;
+       vd = (op>>12) & 0xF;
+
+       switch((op>>24) & 0xF){
+       default:
+               unimp(pc, op);
+       case 0xD:
+               /* 
+                * Extension Register load/store A7.6 
+                */
+               off = (op&0xFF)<<2;
+               if((op & (1<<23)) == 0)
+                       off = -off;
+               ea = REG(ur, o2) + off;
+               switch(o1&0x7){ /* D(Bit 22) = 0 (5l) */
+               default:
+                       unimp(pc, op);
+               case 0:
+                       if(sz)
+                               fst(fpii2d, ea, vd, sz, ufp);
+                       else
+                               fst(fpii2s, ea, vd, sz, ufp);
+                       break;
+               case 1:
+                       if(sz)
+                               fld(fpid2i, vd, ea, sz, ufp);
+                       else
+                               fld(fpis2i, vd, ea, sz, ufp);
+                       break;
+               }
+               break;
+       case 0xE:
+               if(op & (1<<4)){
+                       /* 
+                        * Register transfer between Core & Extension A7.8
+                        */
+                       if(sz)  /* C(Bit 8) != 0 */
+                               unimp(pc, op);
+                       switch(o1){
+                       default:
+                               unimp(pc, op);
+                       case 0: /* Fn := Rt */
+                               *((Word*)&FR(ufp, o2)) = REG(ur, vd);
+                               if(fpemudebug)
+                                       print("MOVWF    R%d, F%d\n", vd, o2);
+                               break;
+                       case 1: /* Rt := Fn */
+                               REG(ur, vd) = *((Word*)&FR(ufp, o2));
+                               if(fpemudebug)
+                                       print("MOVFW    F%d, R%d =%ld\n", o2, vd, REG(ur, vd));
+                               break;
+                       case 0xE:       /* FPSCR := Rt */
+                               ufp->status = REG(ur, vd);
+                               if(fpemudebug)
+                                       print("MOVW     R%d, FPSCR\n", vd);
+                               break;
+                       case 0xF:       /* Rt := FPSCR */
+                               if(vd == 0xF){
+                                       ur->psr = ufp->status;
+                                       if(fpemudebug)
+                                               print("MOVW     FPSCR, PSR\n");
+                               }else{
+                                       REG(ur, vd) = ufp->status;
+                                       if(fpemudebug)
+                                               print("MOVW     FPSCR, R%d\n", vd);
+                               }
+                               break;
+                       }
+               }
+               else{
+                       /*
+                        * VFP data processing instructions A7.5
+                        * Note: As per 5l we ignore (D, N, M) bits
+                        */
+                       if(fpemudebug)
+                               tag = 'F';
+                       o3 = (op>>6) & 0x3;
+                       o4 = op & 0xF;
+                       fm = &FR(ufp, o4);
+
+                       if(o1 == 0xB){  /* A7-17 */
+                               if(o3 & 0x1){
+                                       switch(o2){
+                                       default:
+                                               o = (o2<<1) | (o3>>1);
+                                               break;
+                                       case 0x8:       /* CVT int -> float/double */
+                                               w = *((Word*)fm);
+                                               fpiw2i(&FR(ufp, vd), &w);
+                                               if(fpemudebug)
+                                                       print("CVTW%c   F%d, F%d\n", sz?'D':'F', o4, vd);
+                                               return;
+                                       case 0xD:       /* CVT float/double -> int */
+                                               fpii2w(&w, fm);
+                                               *((Word*)&FR(ufp, vd)) = w;
+                                               if(fpemudebug)
+                                                       print("CVT%cW   F%d, F%d\n", sz?'D':'F', o4, vd);
+                                               return;
+                                       case 0x5:       /* CMPF(E) */
+                                                       fm = &fpconst[0];
+                                                       if(fpemudebug)
+                                                               tag = 'C';
+                                       case 0x4:       /* CMPF(E) */
+                                               ufp->status &= ~(N|C|Z|V);
+                                               ufp->status |= fcmp(&FR(ufp, vd), fm);
+                                               if(fpemudebug)
+                                                       print("CMPF     %c%d,F%d =%#lux\n",
+                                                                       tag, (o2&0x1)? 0: o4, vd, ufp->status>>28);
+                                               return;
+                                       }
+                               }else{  /* VMOV imm (VFPv3 & v4) (5l doesn't generate) */
+                                       vfpoptoi(&fc, o2, o4);
+                                       fm = &fc;
+                                       o = 0;
+                                       if(fpemudebug)
+                                               tag = 'C';
+                               }
+                               FP1 *vfp;
+                               vfp = &voptab1[o];
+                               if(vfp->f == nil)
+                                       unimp(pc, op);
+                               if(fpemudebug)
+                                       print("%s       %c%d,F%d\n", vfp->name, tag, o4, vd);
+                               (*vfp->f)(fm, &FR(ufp, vd));
+                       }
+                       else {  /* A7-16 */
+                               FP2 *vfp;
+                               o = ((o1&0x3)<<1) | (o1&0x8) | (o3&0x1);
+                               vfp = &voptab2[o];
+                               if(vfp->f == nil)
+                                       unimp(pc, op);
+                               if(fpemudebug)
+                                       print("%s       F%d,F%d,F%d\n", vfp->name, o4, o2, vd);
+                               (*vfp->f)(*fm, FR(ufp, o2), &FR(ufp, vd));
+                       }
+               }
+               break;
+       }
+}
+
+
 /*
  * returns the number of FP instructions emulated
  */
@@ -467,6 +646,7 @@ fpiarm(Ureg *ur)
        ulong op, o, cp;
        FPsave *ufp;
        int n;
+       void (*fpemu)(ulong , ulong , Ureg *, FPsave *);
 
        if(up == nil)
                panic("fpiarm not in a process");
@@ -484,7 +664,7 @@ fpiarm(Ureg *ur)
                up->fpstate = FPemu;
                ufp->control = 0;
                ufp->status = (0x01<<28)|(1<<12); /* sw emulation, alt. C flag */
-               for(n = 0; n < 8; n++)
+               for(n = 0; n < Nfpctlregs; n++)
                        FR(ufp, n) = fpconst[0];
        }
        for(n=0; ;n++){
@@ -494,10 +674,15 @@ fpiarm(Ureg *ur)
                        print("%#lux: %#8.8lux ", ur->pc, op);
                o = (op>>24) & 0xF;
                cp = (op>>8) & 0xF;
-               if(!ISFPAOP(cp, o))
+               if(ISFPAOP(cp, o))
+                       fpemu = fpaemu;
+               else if(ISVFPOP(cp, o))
+                       fpemu = vfpemu;
+               else
                        break;
                if(condok(ur->psr, op>>28))
                        fpemu(ur->pc, op, ur, ufp);
+               
                ur->pc += 4;            /* pretend cpu executed the instr */
        }
        if(fpemudebug)
index a9e2ff10002df7c132eea4d4f3d806d5124de774..5b6fc276700edb1758f9e085ab3b9d810aee6b5a 100644 (file)
 #define PsrZ           0x40000000              /* zero */
 #define PsrN           0x80000000              /* negative/less than */
 
+/* instruction decoding */
+#define ISCPOP(op)     ((op) == 0xE || ((op) & ~1) == 0xC)
+#define ISFPAOP(cp, op)        ((cp) == CpOFPA && ISCPOP(op))
+#define ISVFPOP(cp, op)        (((cp) == CpDFP || (cp) == CpFP) && ISCPOP(op))
+
 /*
  * Coprocessors
  */
+#define CpOFPA         1                       /* ancient 7500 FPA */
 #define CpFP           10                      /* float FP, VFP cfg. */
 #define CpDFP          11                      /* double FP */
 #define CpSC           15                      /* System Control */
index 88b901cf6590cb502d57b779f92307c7bb1db10b..f0327bb6a3e1667469d8172a3cb9446cc92ce7db 100644 (file)
@@ -45,6 +45,10 @@ struct Label
        uintptr pc;
 };
 
+enum{
+       Nfpctlregs = 16,
+};
+
 /*
  * emulated floating point
  */
@@ -52,7 +56,7 @@ struct FPsave
 {
        ulong   status;
        ulong   control;
-       ulong   regs[8][3];
+       ulong   regs[Nfpctlregs][3];
 
        int     fpstate;
 };
index 063d10c52abbcbef9aa25828b1e448d87e5bbc6d..99611e0cd681937164327424c47f61c9dbfc8630 100644 (file)
 /* undef this if correct kernel r13 isn't in Ureg;
  * check calculation in fpiarm below
  */
-
-
 #define        REG(ur, x) (*(long*)(((char*)(ur))+roff[(x)]))
-#define        FR(ufp, x) (*(Internal*)(ufp)->regs[(x)&7])
+#define        FR(ufp, x) (*(Internal*)(ufp)->regs[(x)&(Nfpctlregs - 1)])
 
 typedef struct FP2 FP2;
 typedef struct FP1 FP1;
@@ -58,7 +56,7 @@ static        int     roff[] = {
        OFR(r12), OFR(r13), OFR(r14), OFR(pc),
 };
 
-static Internal fpconst[8] = { /* indexed by op&7 */
+static Internal fpconst[8] = {         /* indexed by op&7 (ARM 7500 FPA) */
        /* s, e, l, h */
        {0, 0x1, 0x00000000, 0x00000000}, /* 0.0 */
        {0, 0x3FF, 0x00000000, 0x08000000},     /* 1.0 */
@@ -158,6 +156,10 @@ frnd(Internal *m, Internal *d)
        }
 }
 
+/*
+ * ARM 7500 FPA opcodes
+ */
+
 static FP1     optab1[16] = {  /* Fd := OP Fm */
 [0]    {"MOVF",        fmov},
 [1]    {"NEGF",        fmovn},
@@ -183,6 +185,24 @@ static     FP2     optab2[16] = {  /* Fd := Fn OP Fm */
 /* POL deprecated */
 };
 
+/*
+ * ARM VFP opcodes
+ */
+
+static FP1     voptab1[32] = { /* Vd := OP Vm */
+[0]    {"MOVF",        fmov},
+[1]    {"ABSF",        fabsf},
+[2]    {"NEGF",        fmovn},
+[15]   {"CVTF",        fmov},
+};
+
+static FP2     voptab2[16] = { /* Vd := Vn FOP Fm */
+[4]    {"MULF",        fmul},
+[6]    {"ADDF",        fadd},
+[7]    {"SUBF",        fsub},
+[8]    {"DIVF",        fdiv},
+};
+
 static ulong
 fcmp(Internal *n, Internal *m)
 {
@@ -283,7 +303,7 @@ unimp(ulong pc, ulong op)
 }
 
 static void
-fpemu(ulong pc, ulong op, Ureg *ur, FPsave *ufp)
+fpaemu(ulong pc, ulong op, Ureg *ur, FPsave *ufp)
 {
        int rn, rd, tag, o;
        long off;
@@ -449,6 +469,173 @@ fpemu(ulong pc, ulong op, Ureg *ur, FPsave *ufp)
        }
 }
 
+static void
+vfpoptoi(Internal *fm, uchar o2, uchar o4)
+{
+       fm->s = o2>>3;
+       fm->e = ((o2>>3) | ~(o2 & 4)) - 3 + ExpBias;
+       fm->l = 0;
+       fm->h = o4 << (20+NGuardBits);
+       if(fm->e)
+               fm->h |= HiddenBit;
+       else
+               fm->e++;
+}
+
+static void
+vfpemu(ulong pc, ulong op, Ureg *ur, FPsave *ufp)
+{
+       int sz, vd, o1, o2, o3, o4, o, tag;
+       long off;
+       ulong ea;
+       Word w;
+       
+       Internal *fm, fc;
+
+       /* note: would update fault status here if we noted numeric exceptions */
+
+       sz = op & (1<<8);
+       o1 = (op>>20) & 0xF;
+       o2 = (op>>16) & 0xF;
+       vd = (op>>12) & 0xF;
+
+       switch((op>>24) & 0xF){
+       default:
+               unimp(pc, op);
+       case 0xD:
+               /* 
+                * Extension Register load/store A7.6 
+                */
+               off = (op&0xFF)<<2;
+               if((op & (1<<23)) == 0)
+                       off = -off;
+               ea = REG(ur, o2) + off;
+               switch(o1&0x7){ /* D(Bit 22) = 0 (5l) */
+               default:
+                       unimp(pc, op);
+               case 0:
+                       if(sz)
+                               fst(fpii2d, ea, vd, sz, ufp);
+                       else
+                               fst(fpii2s, ea, vd, sz, ufp);
+                       break;
+               case 1:
+                       if(sz)
+                               fld(fpid2i, vd, ea, sz, ufp);
+                       else
+                               fld(fpis2i, vd, ea, sz, ufp);
+                       break;
+               }
+               break;
+       case 0xE:
+               if(op & (1<<4)){
+                       /* 
+                        * Register transfer between Core & Extension A7.8
+                        */
+                       if(sz)  /* C(Bit 8) != 0 */
+                               unimp(pc, op);
+                       switch(o1){
+                       default:
+                               unimp(pc, op);
+                       case 0: /* Fn := Rt */
+                               *((Word*)&FR(ufp, o2)) = REG(ur, vd);
+                               if(fpemudebug)
+                                       print("MOVWF    R%d, F%d\n", vd, o2);
+                               break;
+                       case 1: /* Rt := Fn */
+                               REG(ur, vd) = *((Word*)&FR(ufp, o2));
+                               if(fpemudebug)
+                                       print("MOVFW    F%d, R%d =%ld\n", o2, vd, REG(ur, vd));
+                               break;
+                       case 0xE:       /* FPSCR := Rt */
+                               ufp->status = REG(ur, vd);
+                               if(fpemudebug)
+                                       print("MOVW     R%d, FPSCR\n", vd);
+                               break;
+                       case 0xF:       /* Rt := FPSCR */
+                               if(vd == 0xF){
+                                       ur->psr = ufp->status;
+                                       if(fpemudebug)
+                                               print("MOVW     FPSCR, PSR\n");
+                               }else{
+                                       REG(ur, vd) = ufp->status;
+                                       if(fpemudebug)
+                                               print("MOVW     FPSCR, R%d\n", vd);
+                               }
+                               break;
+                       }
+               }
+               else{
+                       /*
+                        * VFP data processing instructions A7.5
+                        * Note: As per 5l we ignore (D, N, M) bits
+                        */
+                       if(fpemudebug)
+                               tag = 'F';
+                       o3 = (op>>6) & 0x3;
+                       o4 = op & 0xF;
+                       fm = &FR(ufp, o4);
+
+                       if(o1 == 0xB){  /* A7-17 */
+                               if(o3 & 0x1){
+                                       switch(o2){
+                                       default:
+                                               o = (o2<<1) | (o3>>1);
+                                               break;
+                                       case 0x8:       /* CVT int -> float/double */
+                                               w = *((Word*)fm);
+                                               fpiw2i(&FR(ufp, vd), &w);
+                                               if(fpemudebug)
+                                                       print("CVTW%c   F%d, F%d\n", sz?'D':'F', o4, vd);
+                                               return;
+                                       case 0xD:       /* CVT float/double -> int */
+                                               fpii2w(&w, fm);
+                                               *((Word*)&FR(ufp, vd)) = w;
+                                               if(fpemudebug)
+                                                       print("CVT%cW   F%d, F%d\n", sz?'D':'F', o4, vd);
+                                               return;
+                                       case 0x5:       /* CMPF(E) */
+                                                       fm = &fpconst[0];
+                                                       if(fpemudebug)
+                                                               tag = 'C';
+                                       case 0x4:       /* CMPF(E) */
+                                               ufp->status &= ~(N|C|Z|V);
+                                               ufp->status |= fcmp(&FR(ufp, vd), fm);
+                                               if(fpemudebug)
+                                                       print("CMPF     %c%d,F%d =%#lux\n",
+                                                                       tag, (o2&0x1)? 0: o4, vd, ufp->status>>28);
+                                               return;
+                                       }
+                               }else{  /* VMOV imm (VFPv3 & v4) (5l doesn't generate) */
+                                       vfpoptoi(&fc, o2, o4);
+                                       fm = &fc;
+                                       o = 0;
+                                       if(fpemudebug)
+                                               tag = 'C';
+                               }
+                               FP1 *vfp;
+                               vfp = &voptab1[o];
+                               if(vfp->f == nil)
+                                       unimp(pc, op);
+                               if(fpemudebug)
+                                       print("%s       %c%d,F%d\n", vfp->name, tag, o4, vd);
+                               (*vfp->f)(fm, &FR(ufp, vd));
+                       }
+                       else {  /* A7-16 */
+                               FP2 *vfp;
+                               o = ((o1&0x3)<<1) | (o1&0x8) | (o3&0x1);
+                               vfp = &voptab2[o];
+                               if(vfp->f == nil)
+                                       unimp(pc, op);
+                               if(fpemudebug)
+                                       print("%s       F%d,F%d,F%d\n", vfp->name, o4, o2, vd);
+                               (*vfp->f)(*fm, FR(ufp, o2), &FR(ufp, vd));
+                       }
+               }
+               break;
+       }
+}
+
 void
 casemu(ulong pc, ulong op, Ureg *ur)
 {
@@ -533,14 +720,16 @@ struct {
 int
 fpiarm(Ureg *ur)
 {
-       ulong op, o;
+       ulong op, o, cp;
        FPsave *ufp;
        int i, n;
+       void (*fpemu)(ulong , ulong , Ureg *, FPsave *);
 
        if(up == nil)
                panic("fpiarm not in a process");
        ufp = &up->fpsave;
-       /* because all the state is in the proc structure,
+       /*
+        * because all the emulated fp state is in the proc structure,
         * it need not be saved/restored
         */
        if(up->fpstate != FPactive){
@@ -548,7 +737,7 @@ fpiarm(Ureg *ur)
                up->fpstate = FPactive;
                ufp->control = 0;
                ufp->status = (0x01<<28)|(1<<12);       /* software emulation, alternative C flag */
-               for(n = 0; n < 8; n++)
+               for(n = 0; n < Nfpctlregs; n++)
                        FR(ufp, n) = fpconst[0];
        }
        for(n=0; ;n++){
@@ -557,20 +746,26 @@ fpiarm(Ureg *ur)
                if(fpemudebug)
                        print("%#lux: %#8.8lux ", ur->pc, op);
                o = (op>>24) & 0xF;
-               if(condok(ur->psr, op>>28)){
-                       for(i = 0; specialopc[i].f; i++)
-                               if((op & specialopc[i].mask) == specialopc[i].opc)
-                                       break;
-                       if(specialopc[i].f)
-                               specialopc[i].f(ur->pc, op, ur);
-                       else if((op & 0xF00) != 0x100 || o != 0xE && (o&~1) != 0xC)
+               cp = (op>>8) & 0xF;
+               for(i = 0; specialopc[i].f; i++)
+                       if((op & specialopc[i].mask) == specialopc[i].opc)
                                break;
-                       else
-                               fpemu(ur->pc, op, ur, ufp);
-               }else if((op & 0xF00) != 0x100 || o != 0xE && (o&~1) != 0xC)
+               if(specialopc[i].f)
+                       specialopc[i].f(ur->pc, op, ur);
+               else if(ISVFPOP(cp, o)){
+                       if(condok(ur->psr, op>>28))
+                               vfpemu(ur->pc, op, ur, ufp);
+               }
+               else if(ISFPAOP(cp, o)){
+                       if(condok(ur->psr, op>>28))
+                               fpaemu(ur->pc, op, ur, ufp);
+               }
+               else
                        break;
-               ur->pc += 4;
+
+               ur->pc += 4;            /* pretend cpu executed the instr */
        }
-       if(fpemudebug) print("\n");
+       if(fpemudebug)
+               print("\n");
        return n;
 }
index 0376f36fbc9170f1089d77d1c1e554d221505dc2..250a0ba4206986bc4684d05e234105126fffa7c3 100644 (file)
 #define PsrZ           0x40000000              /* zero */
 #define PsrN           0x80000000              /* negative/less than */
 
+/* instruction decoding */
+#define ISCPOP(op)     ((op) == 0xE || ((op) & ~1) == 0xC)
+#define ISFPAOP(cp, op)        ((cp) == CpOFPA && ISCPOP(op))
+#define ISVFPOP(cp, op)        (((cp) == CpDFP || (cp) == CpFP) && ISCPOP(op))
+
 /*
  * Coprocessors
  */
+#define CpOFPA         1                       /* ancient 7500 FPA */
 #define CpFP           10                      /* float FP, VFP cfg. */
 #define CpDFP          11                      /* double FP */
 #define CpSC           15                      /* System Control */
index 37114691d921486664985fa43d8bbb7f0ef87834..6ed388c155b43cc01fcf5b01878113dbfc588e3b 100644 (file)
@@ -69,6 +69,10 @@ struct Label
        uintptr pc;
 };
 
+enum{
+       Nfpctlregs = 16,
+};
+
 /*
  * emulated floating point
  */
@@ -76,7 +80,7 @@ struct FPsave
 {
        ulong   status;
        ulong   control;
-       ulong   regs[8][3];
+       ulong   regs[Nfpctlregs][3];
 
        int     fpstate;
 };
index 063d10c52abbcbef9aa25828b1e448d87e5bbc6d..99611e0cd681937164327424c47f61c9dbfc8630 100644 (file)
 /* undef this if correct kernel r13 isn't in Ureg;
  * check calculation in fpiarm below
  */
-
-
 #define        REG(ur, x) (*(long*)(((char*)(ur))+roff[(x)]))
-#define        FR(ufp, x) (*(Internal*)(ufp)->regs[(x)&7])
+#define        FR(ufp, x) (*(Internal*)(ufp)->regs[(x)&(Nfpctlregs - 1)])
 
 typedef struct FP2 FP2;
 typedef struct FP1 FP1;
@@ -58,7 +56,7 @@ static        int     roff[] = {
        OFR(r12), OFR(r13), OFR(r14), OFR(pc),
 };
 
-static Internal fpconst[8] = { /* indexed by op&7 */
+static Internal fpconst[8] = {         /* indexed by op&7 (ARM 7500 FPA) */
        /* s, e, l, h */
        {0, 0x1, 0x00000000, 0x00000000}, /* 0.0 */
        {0, 0x3FF, 0x00000000, 0x08000000},     /* 1.0 */
@@ -158,6 +156,10 @@ frnd(Internal *m, Internal *d)
        }
 }
 
+/*
+ * ARM 7500 FPA opcodes
+ */
+
 static FP1     optab1[16] = {  /* Fd := OP Fm */
 [0]    {"MOVF",        fmov},
 [1]    {"NEGF",        fmovn},
@@ -183,6 +185,24 @@ static     FP2     optab2[16] = {  /* Fd := Fn OP Fm */
 /* POL deprecated */
 };
 
+/*
+ * ARM VFP opcodes
+ */
+
+static FP1     voptab1[32] = { /* Vd := OP Vm */
+[0]    {"MOVF",        fmov},
+[1]    {"ABSF",        fabsf},
+[2]    {"NEGF",        fmovn},
+[15]   {"CVTF",        fmov},
+};
+
+static FP2     voptab2[16] = { /* Vd := Vn FOP Fm */
+[4]    {"MULF",        fmul},
+[6]    {"ADDF",        fadd},
+[7]    {"SUBF",        fsub},
+[8]    {"DIVF",        fdiv},
+};
+
 static ulong
 fcmp(Internal *n, Internal *m)
 {
@@ -283,7 +303,7 @@ unimp(ulong pc, ulong op)
 }
 
 static void
-fpemu(ulong pc, ulong op, Ureg *ur, FPsave *ufp)
+fpaemu(ulong pc, ulong op, Ureg *ur, FPsave *ufp)
 {
        int rn, rd, tag, o;
        long off;
@@ -449,6 +469,173 @@ fpemu(ulong pc, ulong op, Ureg *ur, FPsave *ufp)
        }
 }
 
+static void
+vfpoptoi(Internal *fm, uchar o2, uchar o4)
+{
+       fm->s = o2>>3;
+       fm->e = ((o2>>3) | ~(o2 & 4)) - 3 + ExpBias;
+       fm->l = 0;
+       fm->h = o4 << (20+NGuardBits);
+       if(fm->e)
+               fm->h |= HiddenBit;
+       else
+               fm->e++;
+}
+
+static void
+vfpemu(ulong pc, ulong op, Ureg *ur, FPsave *ufp)
+{
+       int sz, vd, o1, o2, o3, o4, o, tag;
+       long off;
+       ulong ea;
+       Word w;
+       
+       Internal *fm, fc;
+
+       /* note: would update fault status here if we noted numeric exceptions */
+
+       sz = op & (1<<8);
+       o1 = (op>>20) & 0xF;
+       o2 = (op>>16) & 0xF;
+       vd = (op>>12) & 0xF;
+
+       switch((op>>24) & 0xF){
+       default:
+               unimp(pc, op);
+       case 0xD:
+               /* 
+                * Extension Register load/store A7.6 
+                */
+               off = (op&0xFF)<<2;
+               if((op & (1<<23)) == 0)
+                       off = -off;
+               ea = REG(ur, o2) + off;
+               switch(o1&0x7){ /* D(Bit 22) = 0 (5l) */
+               default:
+                       unimp(pc, op);
+               case 0:
+                       if(sz)
+                               fst(fpii2d, ea, vd, sz, ufp);
+                       else
+                               fst(fpii2s, ea, vd, sz, ufp);
+                       break;
+               case 1:
+                       if(sz)
+                               fld(fpid2i, vd, ea, sz, ufp);
+                       else
+                               fld(fpis2i, vd, ea, sz, ufp);
+                       break;
+               }
+               break;
+       case 0xE:
+               if(op & (1<<4)){
+                       /* 
+                        * Register transfer between Core & Extension A7.8
+                        */
+                       if(sz)  /* C(Bit 8) != 0 */
+                               unimp(pc, op);
+                       switch(o1){
+                       default:
+                               unimp(pc, op);
+                       case 0: /* Fn := Rt */
+                               *((Word*)&FR(ufp, o2)) = REG(ur, vd);
+                               if(fpemudebug)
+                                       print("MOVWF    R%d, F%d\n", vd, o2);
+                               break;
+                       case 1: /* Rt := Fn */
+                               REG(ur, vd) = *((Word*)&FR(ufp, o2));
+                               if(fpemudebug)
+                                       print("MOVFW    F%d, R%d =%ld\n", o2, vd, REG(ur, vd));
+                               break;
+                       case 0xE:       /* FPSCR := Rt */
+                               ufp->status = REG(ur, vd);
+                               if(fpemudebug)
+                                       print("MOVW     R%d, FPSCR\n", vd);
+                               break;
+                       case 0xF:       /* Rt := FPSCR */
+                               if(vd == 0xF){
+                                       ur->psr = ufp->status;
+                                       if(fpemudebug)
+                                               print("MOVW     FPSCR, PSR\n");
+                               }else{
+                                       REG(ur, vd) = ufp->status;
+                                       if(fpemudebug)
+                                               print("MOVW     FPSCR, R%d\n", vd);
+                               }
+                               break;
+                       }
+               }
+               else{
+                       /*
+                        * VFP data processing instructions A7.5
+                        * Note: As per 5l we ignore (D, N, M) bits
+                        */
+                       if(fpemudebug)
+                               tag = 'F';
+                       o3 = (op>>6) & 0x3;
+                       o4 = op & 0xF;
+                       fm = &FR(ufp, o4);
+
+                       if(o1 == 0xB){  /* A7-17 */
+                               if(o3 & 0x1){
+                                       switch(o2){
+                                       default:
+                                               o = (o2<<1) | (o3>>1);
+                                               break;
+                                       case 0x8:       /* CVT int -> float/double */
+                                               w = *((Word*)fm);
+                                               fpiw2i(&FR(ufp, vd), &w);
+                                               if(fpemudebug)
+                                                       print("CVTW%c   F%d, F%d\n", sz?'D':'F', o4, vd);
+                                               return;
+                                       case 0xD:       /* CVT float/double -> int */
+                                               fpii2w(&w, fm);
+                                               *((Word*)&FR(ufp, vd)) = w;
+                                               if(fpemudebug)
+                                                       print("CVT%cW   F%d, F%d\n", sz?'D':'F', o4, vd);
+                                               return;
+                                       case 0x5:       /* CMPF(E) */
+                                                       fm = &fpconst[0];
+                                                       if(fpemudebug)
+                                                               tag = 'C';
+                                       case 0x4:       /* CMPF(E) */
+                                               ufp->status &= ~(N|C|Z|V);
+                                               ufp->status |= fcmp(&FR(ufp, vd), fm);
+                                               if(fpemudebug)
+                                                       print("CMPF     %c%d,F%d =%#lux\n",
+                                                                       tag, (o2&0x1)? 0: o4, vd, ufp->status>>28);
+                                               return;
+                                       }
+                               }else{  /* VMOV imm (VFPv3 & v4) (5l doesn't generate) */
+                                       vfpoptoi(&fc, o2, o4);
+                                       fm = &fc;
+                                       o = 0;
+                                       if(fpemudebug)
+                                               tag = 'C';
+                               }
+                               FP1 *vfp;
+                               vfp = &voptab1[o];
+                               if(vfp->f == nil)
+                                       unimp(pc, op);
+                               if(fpemudebug)
+                                       print("%s       %c%d,F%d\n", vfp->name, tag, o4, vd);
+                               (*vfp->f)(fm, &FR(ufp, vd));
+                       }
+                       else {  /* A7-16 */
+                               FP2 *vfp;
+                               o = ((o1&0x3)<<1) | (o1&0x8) | (o3&0x1);
+                               vfp = &voptab2[o];
+                               if(vfp->f == nil)
+                                       unimp(pc, op);
+                               if(fpemudebug)
+                                       print("%s       F%d,F%d,F%d\n", vfp->name, o4, o2, vd);
+                               (*vfp->f)(*fm, FR(ufp, o2), &FR(ufp, vd));
+                       }
+               }
+               break;
+       }
+}
+
 void
 casemu(ulong pc, ulong op, Ureg *ur)
 {
@@ -533,14 +720,16 @@ struct {
 int
 fpiarm(Ureg *ur)
 {
-       ulong op, o;
+       ulong op, o, cp;
        FPsave *ufp;
        int i, n;
+       void (*fpemu)(ulong , ulong , Ureg *, FPsave *);
 
        if(up == nil)
                panic("fpiarm not in a process");
        ufp = &up->fpsave;
-       /* because all the state is in the proc structure,
+       /*
+        * because all the emulated fp state is in the proc structure,
         * it need not be saved/restored
         */
        if(up->fpstate != FPactive){
@@ -548,7 +737,7 @@ fpiarm(Ureg *ur)
                up->fpstate = FPactive;
                ufp->control = 0;
                ufp->status = (0x01<<28)|(1<<12);       /* software emulation, alternative C flag */
-               for(n = 0; n < 8; n++)
+               for(n = 0; n < Nfpctlregs; n++)
                        FR(ufp, n) = fpconst[0];
        }
        for(n=0; ;n++){
@@ -557,20 +746,26 @@ fpiarm(Ureg *ur)
                if(fpemudebug)
                        print("%#lux: %#8.8lux ", ur->pc, op);
                o = (op>>24) & 0xF;
-               if(condok(ur->psr, op>>28)){
-                       for(i = 0; specialopc[i].f; i++)
-                               if((op & specialopc[i].mask) == specialopc[i].opc)
-                                       break;
-                       if(specialopc[i].f)
-                               specialopc[i].f(ur->pc, op, ur);
-                       else if((op & 0xF00) != 0x100 || o != 0xE && (o&~1) != 0xC)
+               cp = (op>>8) & 0xF;
+               for(i = 0; specialopc[i].f; i++)
+                       if((op & specialopc[i].mask) == specialopc[i].opc)
                                break;
-                       else
-                               fpemu(ur->pc, op, ur, ufp);
-               }else if((op & 0xF00) != 0x100 || o != 0xE && (o&~1) != 0xC)
+               if(specialopc[i].f)
+                       specialopc[i].f(ur->pc, op, ur);
+               else if(ISVFPOP(cp, o)){
+                       if(condok(ur->psr, op>>28))
+                               vfpemu(ur->pc, op, ur, ufp);
+               }
+               else if(ISFPAOP(cp, o)){
+                       if(condok(ur->psr, op>>28))
+                               fpaemu(ur->pc, op, ur, ufp);
+               }
+               else
                        break;
-               ur->pc += 4;
+
+               ur->pc += 4;            /* pretend cpu executed the instr */
        }
-       if(fpemudebug) print("\n");
+       if(fpemudebug)
+               print("\n");
        return n;
 }
index 571e89fa6c3a7296146a655efdec209bead651b0..d92455328e0ee8999f52126832d104f709f4f546 100644 (file)
 #include       "arm.h"
 #include       "fpi.h"
 
-#define ARM7500                        /* emulate old pre-VFP opcodes */
-
 /* undef this if correct kernel r13 isn't in Ureg;
  * check calculation in fpiarm below
  */
-
 #define        REG(ur, x) (*(long*)(((char*)(ur))+roff[(x)]))
-#ifdef ARM7500
-#define        FR(ufp, x) (*(Internal*)(ufp)->regs[(x)&7])
-#else
-#define        FR(ufp, x) (*(Internal*)(ufp)->regs[(x)&(Nfpregs - 1)])
-#endif
+#define        FR(ufp, x) (*(Internal*)(ufp)->regs[(x)&(Nfpctlregs - 1)])
 
 typedef struct FP2 FP2;
 typedef struct FP1 FP1;
@@ -192,6 +185,24 @@ static     FP2     optab2[16] = {  /* Fd := Fn OP Fm */
 /* POL deprecated */
 };
 
+/*
+ * ARM VFP opcodes
+ */
+
+static FP1     voptab1[32] = { /* Vd := OP Vm */
+[0]    {"MOVF",        fmov},
+[1]    {"ABSF",        fabsf},
+[2]    {"NEGF",        fmovn},
+[15]   {"CVTF",        fmov},
+};
+
+static FP2     voptab2[16] = { /* Vd := Vn FOP Fm */
+[4]    {"MULF",        fmul},
+[6]    {"ADDF",        fadd},
+[7]    {"SUBF",        fsub},
+[8]    {"DIVF",        fdiv},
+};
+
 static ulong
 fcmp(Internal *n, Internal *m)
 {
@@ -292,7 +303,7 @@ unimp(ulong pc, ulong op)
 }
 
 static void
-fpemu(ulong pc, ulong op, Ureg *ur, FPsave *ufp)
+fpaemu(ulong pc, ulong op, Ureg *ur, FPsave *ufp)
 {
        int rn, rd, tag, o;
        long off;
@@ -458,6 +469,174 @@ fpemu(ulong pc, ulong op, Ureg *ur, FPsave *ufp)
        }
 }
 
+static void
+vfpoptoi(Internal *fm, uchar o2, uchar o4)
+{
+       fm->s = o2>>3;
+       fm->e = ((o2>>3) | ~(o2 & 4)) - 3 + ExpBias;
+       fm->l = 0;
+       fm->h = o4 << (20+NGuardBits);
+       if(fm->e)
+               fm->h |= HiddenBit;
+       else
+               fm->e++;
+}
+
+static void
+vfpemu(ulong pc, ulong op, Ureg *ur, FPsave *ufp)
+{
+       int sz, vd, o1, o2, o3, o4, o, tag;
+       long off;
+       ulong ea;
+       Word w;
+       
+       Internal *fm, fc;
+
+       /* note: would update fault status here if we noted numeric exceptions */
+
+       sz = op & (1<<8);
+       o1 = (op>>20) & 0xF;
+       o2 = (op>>16) & 0xF;
+       vd = (op>>12) & 0xF;
+
+       switch((op>>24) & 0xF){
+       default:
+               unimp(pc, op);
+       case 0xD:
+               /* 
+                * Extension Register load/store A7.6 
+                */
+               off = (op&0xFF)<<2;
+               if((op & (1<<23)) == 0)
+                       off = -off;
+               ea = REG(ur, o2) + off;
+               switch(o1&0x7){ /* D(Bit 22) = 0 (5l) */
+               default:
+                       unimp(pc, op);
+               case 0:
+                       if(sz)
+                               fst(fpii2d, ea, vd, sz, ufp);
+                       else
+                               fst(fpii2s, ea, vd, sz, ufp);
+                       break;
+               case 1:
+                       if(sz)
+                               fld(fpid2i, vd, ea, sz, ufp);
+                       else
+                               fld(fpis2i, vd, ea, sz, ufp);
+                       break;
+               }
+               break;
+       case 0xE:
+               if(op & (1<<4)){
+                       /* 
+                        * Register transfer between Core & Extension A7.8
+                        */
+                       if(sz)  /* C(Bit 8) != 0 */
+                               unimp(pc, op);
+                       switch(o1){
+                       default:
+                               unimp(pc, op);
+                       case 0: /* Fn := Rt */
+                               *((Word*)&FR(ufp, o2)) = REG(ur, vd);
+                               if(fpemudebug)
+                                       print("MOVWF    R%d, F%d\n", vd, o2);
+                               break;
+                       case 1: /* Rt := Fn */
+                               REG(ur, vd) = *((Word*)&FR(ufp, o2));
+                               if(fpemudebug)
+                                       print("MOVFW    F%d, R%d =%ld\n", o2, vd, REG(ur, vd));
+                               break;
+                       case 0xE:       /* FPSCR := Rt */
+                               ufp->status = REG(ur, vd);
+                               if(fpemudebug)
+                                       print("MOVW     R%d, FPSCR\n", vd);
+                               break;
+                       case 0xF:       /* Rt := FPSCR */
+                               if(vd == 0xF){
+                                       ur->psr = ufp->status;
+                                       if(fpemudebug)
+                                               print("MOVW     FPSCR, PSR\n");
+                               }else{
+                                       REG(ur, vd) = ufp->status;
+                                       if(fpemudebug)
+                                               print("MOVW     FPSCR, R%d\n", vd);
+                               }
+                               break;
+                       }
+               }
+               else{
+                       /*
+                        * VFP data processing instructions A7.5
+                        * Note: As per 5l we ignore (D, N, M) bits
+                        */
+                       if(fpemudebug)
+                               tag = 'F';
+                       o3 = (op>>6) & 0x3;
+                       o4 = op & 0xF;
+                       fm = &FR(ufp, o4);
+
+                       if(o1 == 0xB){  /* A7-17 */
+                               if(o3 & 0x1){
+                                       switch(o2){
+                                       default:
+                                               o = (o2<<1) | (o3>>1);
+                                               break;
+                                       case 0x8:       /* CVT int -> float/double */
+                                               w = *((Word*)fm);
+                                               fpiw2i(&FR(ufp, vd), &w);
+                                               if(fpemudebug)
+                                                       print("CVTW%c   F%d, F%d\n", sz?'D':'F', o4, vd);
+                                               return;
+                                       case 0xD:       /* CVT float/double -> int */
+                                               fpii2w(&w, fm);
+                                               *((Word*)&FR(ufp, vd)) = w;
+                                               if(fpemudebug)
+                                                       print("CVT%cW   F%d, F%d\n", sz?'D':'F', o4, vd);
+                                               return;
+                                       case 0x5:       /* CMPF(E) */
+                                                       fm = &fpconst[0];
+                                                       if(fpemudebug)
+                                                               tag = 'C';
+                                       case 0x4:       /* CMPF(E) */
+                                               ufp->status &= ~(N|C|Z|V);
+                                               ufp->status |= fcmp(&FR(ufp, vd), fm);
+                                               if(fpemudebug)
+                                                       print("CMPF     %c%d,F%d =%#lux\n",
+                                                                       tag, (o2&0x1)? 0: o4, vd, ufp->status>>28);
+                                               return;
+                                       }
+                               }else{  /* VMOV imm (VFPv3 & v4) (5l doesn't generate) */
+                                       vfpoptoi(&fc, o2, o4);
+                                       fm = &fc;
+                                       o = 0;
+                                       if(fpemudebug)
+                                               tag = 'C';
+                               }
+                               FP1 *vfp;
+                               vfp = &voptab1[o];
+                               if(vfp->f == nil)
+                                       unimp(pc, op);
+                               if(fpemudebug)
+                                       print("%s       %c%d,F%d\n", vfp->name, tag, o4, vd);
+                               (*vfp->f)(fm, &FR(ufp, vd));
+                       }
+                       else {  /* A7-16 */
+                               FP2 *vfp;
+                               o = ((o1&0x3)<<1) | (o1&0x8) | (o3&0x1);
+                               vfp = &voptab2[o];
+                               if(vfp->f == nil)
+                                       unimp(pc, op);
+                               if(fpemudebug)
+                                       print("%s       F%d,F%d,F%d\n", vfp->name, o4, o2, vd);
+                               (*vfp->f)(*fm, FR(ufp, o2), &FR(ufp, vd));
+                       }
+               }
+               break;
+       }
+}
+
+
 /*
  * returns the number of FP instructions emulated
  */
@@ -467,6 +646,7 @@ fpiarm(Ureg *ur)
        ulong op, o, cp;
        FPsave *ufp;
        int n;
+       void (*fpemu)(ulong , ulong , Ureg *, FPsave *);
 
        if(up == nil)
                panic("fpiarm not in a process");
@@ -484,7 +664,7 @@ fpiarm(Ureg *ur)
                up->fpstate = FPemu;
                ufp->control = 0;
                ufp->status = (0x01<<28)|(1<<12); /* sw emulation, alt. C flag */
-               for(n = 0; n < 8; n++)
+               for(n = 0; n < Nfpctlregs; n++)
                        FR(ufp, n) = fpconst[0];
        }
        for(n=0; ;n++){
@@ -494,10 +674,15 @@ fpiarm(Ureg *ur)
                        print("%#lux: %#8.8lux ", ur->pc, op);
                o = (op>>24) & 0xF;
                cp = (op>>8) & 0xF;
-               if(!ISFPAOP(cp, o))
+               if(ISFPAOP(cp, o))
+                       fpemu = fpaemu;
+               else if(ISVFPOP(cp, o))
+                       fpemu = vfpemu;
+               else
                        break;
                if(condok(ur->psr, op>>28))
                        fpemu(ur->pc, op, ur, ufp);
+               
                ur->pc += 4;            /* pretend cpu executed the instr */
        }
        if(fpemudebug)