17bb09086SDavid du Colombier /*
27bb09086SDavid du Colombier * this doesn't attempt to implement ARM floating-point properties
37bb09086SDavid du Colombier * that aren't visible in the Inferno environment.
47bb09086SDavid du Colombier * all arithmetic is done in double precision.
57bb09086SDavid du Colombier * the FP trap status isn't updated.
67bb09086SDavid du Colombier */
77bb09086SDavid du Colombier #include "u.h"
87bb09086SDavid du Colombier #include "../port/lib.h"
97bb09086SDavid du Colombier #include "mem.h"
107bb09086SDavid du Colombier #include "dat.h"
117bb09086SDavid du Colombier #include "fns.h"
127bb09086SDavid du Colombier
137bb09086SDavid du Colombier #include "ureg.h"
147bb09086SDavid du Colombier
157bb09086SDavid du Colombier #include "arm.h"
16*d11907f1SDavid du Colombier #include "../port/fpi.h"
177bb09086SDavid du Colombier
187bb09086SDavid du Colombier /* undef this if correct kernel r13 isn't in Ureg;
197bb09086SDavid du Colombier * check calculation in fpiarm below
207bb09086SDavid du Colombier */
217bb09086SDavid du Colombier
227bb09086SDavid du Colombier
237bb09086SDavid du Colombier #define REG(ur, x) (*(long*)(((char*)(ur))+roff[(x)]))
247bb09086SDavid du Colombier #define FR(ufp, x) (*(Internal*)(ufp)->regs[(x)&7])
257bb09086SDavid du Colombier
267bb09086SDavid du Colombier typedef struct FP2 FP2;
277bb09086SDavid du Colombier typedef struct FP1 FP1;
287bb09086SDavid du Colombier
297bb09086SDavid du Colombier struct FP2 {
307bb09086SDavid du Colombier char* name;
317bb09086SDavid du Colombier void (*f)(Internal, Internal, Internal*);
327bb09086SDavid du Colombier };
337bb09086SDavid du Colombier
347bb09086SDavid du Colombier struct FP1 {
357bb09086SDavid du Colombier char* name;
367bb09086SDavid du Colombier void (*f)(Internal*, Internal*);
377bb09086SDavid du Colombier };
387bb09086SDavid du Colombier
397bb09086SDavid du Colombier enum {
407bb09086SDavid du Colombier N = 1<<31,
417bb09086SDavid du Colombier Z = 1<<30,
427bb09086SDavid du Colombier C = 1<<29,
437bb09086SDavid du Colombier V = 1<<28,
447bb09086SDavid du Colombier REGPC = 15,
457bb09086SDavid du Colombier };
467bb09086SDavid du Colombier
477bb09086SDavid du Colombier enum {
487bb09086SDavid du Colombier fpemudebug = 0,
497bb09086SDavid du Colombier };
507bb09086SDavid du Colombier
517bb09086SDavid du Colombier #undef OFR
527bb09086SDavid du Colombier #define OFR(X) ((ulong)&((Ureg*)0)->X)
537bb09086SDavid du Colombier
547bb09086SDavid du Colombier static int roff[] = {
557bb09086SDavid du Colombier OFR(r0), OFR(r1), OFR(r2), OFR(r3),
567bb09086SDavid du Colombier OFR(r4), OFR(r5), OFR(r6), OFR(r7),
577bb09086SDavid du Colombier OFR(r8), OFR(r9), OFR(r10), OFR(r11),
587bb09086SDavid du Colombier OFR(r12), OFR(r13), OFR(r14), OFR(pc),
597bb09086SDavid du Colombier };
607bb09086SDavid du Colombier
617bb09086SDavid du Colombier static Internal fpconst[8] = { /* indexed by op&7 */
627bb09086SDavid du Colombier /* s, e, l, h */
637bb09086SDavid du Colombier {0, 0x1, 0x00000000, 0x00000000}, /* 0.0 */
647bb09086SDavid du Colombier {0, 0x3FF, 0x00000000, 0x08000000}, /* 1.0 */
657bb09086SDavid du Colombier {0, 0x400, 0x00000000, 0x08000000}, /* 2.0 */
667bb09086SDavid du Colombier {0, 0x400, 0x00000000, 0x0C000000}, /* 3.0 */
677bb09086SDavid du Colombier {0, 0x401, 0x00000000, 0x08000000}, /* 4.0 */
687bb09086SDavid du Colombier {0, 0x401, 0x00000000, 0x0A000000}, /* 5.0 */
697bb09086SDavid du Colombier {0, 0x3FE, 0x00000000, 0x08000000}, /* 0.5 */
707bb09086SDavid du Colombier {0, 0x402, 0x00000000, 0x0A000000}, /* 10.0 */
717bb09086SDavid du Colombier };
727bb09086SDavid du Colombier
737bb09086SDavid du Colombier /*
747bb09086SDavid du Colombier * arm binary operations
757bb09086SDavid du Colombier */
767bb09086SDavid du Colombier
777bb09086SDavid du Colombier static void
fadd(Internal m,Internal n,Internal * d)787bb09086SDavid du Colombier fadd(Internal m, Internal n, Internal *d)
797bb09086SDavid du Colombier {
807bb09086SDavid du Colombier (m.s == n.s? fpiadd: fpisub)(&m, &n, d);
817bb09086SDavid du Colombier }
827bb09086SDavid du Colombier
837bb09086SDavid du Colombier static void
fsub(Internal m,Internal n,Internal * d)847bb09086SDavid du Colombier fsub(Internal m, Internal n, Internal *d)
857bb09086SDavid du Colombier {
867bb09086SDavid du Colombier m.s ^= 1;
877bb09086SDavid du Colombier (m.s == n.s? fpiadd: fpisub)(&m, &n, d);
887bb09086SDavid du Colombier }
897bb09086SDavid du Colombier
907bb09086SDavid du Colombier static void
fsubr(Internal m,Internal n,Internal * d)917bb09086SDavid du Colombier fsubr(Internal m, Internal n, Internal *d)
927bb09086SDavid du Colombier {
937bb09086SDavid du Colombier n.s ^= 1;
947bb09086SDavid du Colombier (n.s == m.s? fpiadd: fpisub)(&n, &m, d);
957bb09086SDavid du Colombier }
967bb09086SDavid du Colombier
977bb09086SDavid du Colombier static void
fmul(Internal m,Internal n,Internal * d)987bb09086SDavid du Colombier fmul(Internal m, Internal n, Internal *d)
997bb09086SDavid du Colombier {
1007bb09086SDavid du Colombier fpimul(&m, &n, d);
1017bb09086SDavid du Colombier }
1027bb09086SDavid du Colombier
1037bb09086SDavid du Colombier static void
fdiv(Internal m,Internal n,Internal * d)1047bb09086SDavid du Colombier fdiv(Internal m, Internal n, Internal *d)
1057bb09086SDavid du Colombier {
1067bb09086SDavid du Colombier fpidiv(&m, &n, d);
1077bb09086SDavid du Colombier }
1087bb09086SDavid du Colombier
1097bb09086SDavid du Colombier static void
fdivr(Internal m,Internal n,Internal * d)1107bb09086SDavid du Colombier fdivr(Internal m, Internal n, Internal *d)
1117bb09086SDavid du Colombier {
1127bb09086SDavid du Colombier fpidiv(&n, &m, d);
1137bb09086SDavid du Colombier }
1147bb09086SDavid du Colombier
1157bb09086SDavid du Colombier /*
1167bb09086SDavid du Colombier * arm unary operations
1177bb09086SDavid du Colombier */
1187bb09086SDavid du Colombier
1197bb09086SDavid du Colombier static void
fmov(Internal * m,Internal * d)1207bb09086SDavid du Colombier fmov(Internal *m, Internal *d)
1217bb09086SDavid du Colombier {
1227bb09086SDavid du Colombier *d = *m;
1237bb09086SDavid du Colombier }
1247bb09086SDavid du Colombier
1257bb09086SDavid du Colombier static void
fmovn(Internal * m,Internal * d)1267bb09086SDavid du Colombier fmovn(Internal *m, Internal *d)
1277bb09086SDavid du Colombier {
1287bb09086SDavid du Colombier *d = *m;
1297bb09086SDavid du Colombier d->s ^= 1;
1307bb09086SDavid du Colombier }
1317bb09086SDavid du Colombier
1327bb09086SDavid du Colombier static void
fabsf(Internal * m,Internal * d)1337bb09086SDavid du Colombier fabsf(Internal *m, Internal *d)
1347bb09086SDavid du Colombier {
1357bb09086SDavid du Colombier *d = *m;
1367bb09086SDavid du Colombier d->s = 0;
1377bb09086SDavid du Colombier }
1387bb09086SDavid du Colombier
1397bb09086SDavid du Colombier static void
frnd(Internal * m,Internal * d)1407bb09086SDavid du Colombier frnd(Internal *m, Internal *d)
1417bb09086SDavid du Colombier {
1427bb09086SDavid du Colombier short e;
1437bb09086SDavid du Colombier
1447bb09086SDavid du Colombier (m->s? fsub: fadd)(fpconst[6], *m, d);
1457bb09086SDavid du Colombier if(IsWeird(d))
1467bb09086SDavid du Colombier return;
1477bb09086SDavid du Colombier fpiround(d);
1487bb09086SDavid du Colombier e = (d->e - ExpBias) + 1;
1497bb09086SDavid du Colombier if(e <= 0)
1507bb09086SDavid du Colombier SetZero(d);
1517bb09086SDavid du Colombier else if(e > FractBits){
1527bb09086SDavid du Colombier if(e < 2*FractBits)
1537bb09086SDavid du Colombier d->l &= ~((1<<(2*FractBits - e))-1);
1547bb09086SDavid du Colombier }else{
1557bb09086SDavid du Colombier d->l = 0;
1567bb09086SDavid du Colombier if(e < FractBits)
1577bb09086SDavid du Colombier d->h &= ~((1<<(FractBits-e))-1);
1587bb09086SDavid du Colombier }
1597bb09086SDavid du Colombier }
1607bb09086SDavid du Colombier
1617bb09086SDavid du Colombier static FP1 optab1[16] = { /* Fd := OP Fm */
1627bb09086SDavid du Colombier [0] {"MOVF", fmov},
1637bb09086SDavid du Colombier [1] {"NEGF", fmovn},
1647bb09086SDavid du Colombier [2] {"ABSF", fabsf},
1657bb09086SDavid du Colombier [3] {"RNDF", frnd},
1667bb09086SDavid du Colombier [4] {"SQTF", /*fsqt*/0},
1677bb09086SDavid du Colombier /* LOG, LGN, EXP, SIN, COS, TAN, ASN, ACS, ATN all `deprecated' */
1687bb09086SDavid du Colombier /* URD and NRM aren't implemented */
1697bb09086SDavid du Colombier };
1707bb09086SDavid du Colombier
1717bb09086SDavid du Colombier static FP2 optab2[16] = { /* Fd := Fn OP Fm */
1727bb09086SDavid du Colombier [0] {"ADDF", fadd},
1737bb09086SDavid du Colombier [1] {"MULF", fmul},
1747bb09086SDavid du Colombier [2] {"SUBF", fsub},
1757bb09086SDavid du Colombier [3] {"RSUBF", fsubr},
1767bb09086SDavid du Colombier [4] {"DIVF", fdiv},
1777bb09086SDavid du Colombier [5] {"RDIVF", fdivr},
1787bb09086SDavid du Colombier /* POW, RPW deprecated */
1797bb09086SDavid du Colombier [8] {"REMF", /*frem*/0},
1807bb09086SDavid du Colombier [9] {"FMF", fmul}, /* fast multiply */
1817bb09086SDavid du Colombier [10] {"FDV", fdiv}, /* fast divide */
1827bb09086SDavid du Colombier [11] {"FRD", fdivr}, /* fast reverse divide */
1837bb09086SDavid du Colombier /* POL deprecated */
1847bb09086SDavid du Colombier };
1857bb09086SDavid du Colombier
1867bb09086SDavid du Colombier static ulong
fcmp(Internal * n,Internal * m)1877bb09086SDavid du Colombier fcmp(Internal *n, Internal *m)
1887bb09086SDavid du Colombier {
1897bb09086SDavid du Colombier int i;
1907bb09086SDavid du Colombier Internal rm, rn;
1917bb09086SDavid du Colombier
1927bb09086SDavid du Colombier if(IsWeird(m) || IsWeird(n)){
1937bb09086SDavid du Colombier /* BUG: should trap if not masked */
1947bb09086SDavid du Colombier return V|C;
1957bb09086SDavid du Colombier }
1967bb09086SDavid du Colombier rn = *n;
1977bb09086SDavid du Colombier rm = *m;
1987bb09086SDavid du Colombier fpiround(&rn);
1997bb09086SDavid du Colombier fpiround(&rm);
2007bb09086SDavid du Colombier i = fpicmp(&rn, &rm);
2017bb09086SDavid du Colombier if(i > 0)
2027bb09086SDavid du Colombier return C;
2037bb09086SDavid du Colombier else if(i == 0)
2047bb09086SDavid du Colombier return C|Z;
2057bb09086SDavid du Colombier else
2067bb09086SDavid du Colombier return N;
2077bb09086SDavid du Colombier }
2087bb09086SDavid du Colombier
2097bb09086SDavid du Colombier static void
fld(void (* f)(Internal *,void *),int d,ulong ea,int n,FPsave * ufp)2107bb09086SDavid du Colombier fld(void (*f)(Internal*, void*), int d, ulong ea, int n, FPsave *ufp)
2117bb09086SDavid du Colombier {
2127bb09086SDavid du Colombier void *mem;
2137bb09086SDavid du Colombier
2147bb09086SDavid du Colombier mem = (void*)ea;
2157bb09086SDavid du Colombier (*f)(&FR(ufp, d), mem);
2167bb09086SDavid du Colombier if(fpemudebug)
2177bb09086SDavid du Colombier print("MOV%c #%lux, F%d\n", n==8? 'D': 'F', ea, d);
2187bb09086SDavid du Colombier }
2197bb09086SDavid du Colombier
2207bb09086SDavid du Colombier static void
fst(void (* f)(void *,Internal *),ulong ea,int s,int n,FPsave * ufp)2217bb09086SDavid du Colombier fst(void (*f)(void*, Internal*), ulong ea, int s, int n, FPsave *ufp)
2227bb09086SDavid du Colombier {
2237bb09086SDavid du Colombier Internal tmp;
2247bb09086SDavid du Colombier void *mem;
2257bb09086SDavid du Colombier
2267bb09086SDavid du Colombier mem = (void*)ea;
2277bb09086SDavid du Colombier tmp = FR(ufp, s);
2287bb09086SDavid du Colombier if(fpemudebug)
2297bb09086SDavid du Colombier print("MOV%c F%d,#%lux\n", n==8? 'D': 'F', s, ea);
2307bb09086SDavid du Colombier (*f)(mem, &tmp);
2317bb09086SDavid du Colombier }
2327bb09086SDavid du Colombier
2337bb09086SDavid du Colombier static int
condok(int cc,int c)2347bb09086SDavid du Colombier condok(int cc, int c)
2357bb09086SDavid du Colombier {
2367bb09086SDavid du Colombier switch(c){
2377bb09086SDavid du Colombier case 0: /* Z set */
2387bb09086SDavid du Colombier return cc&Z;
2397bb09086SDavid du Colombier case 1: /* Z clear */
2407bb09086SDavid du Colombier return (cc&Z) == 0;
2417bb09086SDavid du Colombier case 2: /* C set */
2427bb09086SDavid du Colombier return cc&C;
2437bb09086SDavid du Colombier case 3: /* C clear */
2447bb09086SDavid du Colombier return (cc&C) == 0;
2457bb09086SDavid du Colombier case 4: /* N set */
2467bb09086SDavid du Colombier return cc&N;
2477bb09086SDavid du Colombier case 5: /* N clear */
2487bb09086SDavid du Colombier return (cc&N) == 0;
2497bb09086SDavid du Colombier case 6: /* V set */
2507bb09086SDavid du Colombier return cc&V;
2517bb09086SDavid du Colombier case 7: /* V clear */
2527bb09086SDavid du Colombier return (cc&V) == 0;
2537bb09086SDavid du Colombier case 8: /* C set and Z clear */
2547bb09086SDavid du Colombier return cc&C && (cc&Z) == 0;
2557bb09086SDavid du Colombier case 9: /* C clear or Z set */
2567bb09086SDavid du Colombier return (cc&C) == 0 || cc&Z;
2577bb09086SDavid du Colombier case 10: /* N set and V set, or N clear and V clear */
2587bb09086SDavid du Colombier return (~cc&(N|V))==0 || (cc&(N|V)) == 0;
2597bb09086SDavid du Colombier case 11: /* N set and V clear, or N clear and V set */
2607bb09086SDavid du Colombier return (cc&(N|V))==N || (cc&(N|V))==V;
2617bb09086SDavid du Colombier case 12: /* Z clear, and either N set and V set or N clear and V clear */
2627bb09086SDavid du Colombier return (cc&Z) == 0 && ((~cc&(N|V))==0 || (cc&(N|V))==0);
2637bb09086SDavid du Colombier case 13: /* Z set, or N set and V clear or N clear and V set */
2647bb09086SDavid du Colombier return (cc&Z) || (cc&(N|V))==N || (cc&(N|V))==V;
2657bb09086SDavid du Colombier case 14: /* always */
2667bb09086SDavid du Colombier return 1;
2677bb09086SDavid du Colombier case 15: /* never (reserved) */
2687bb09086SDavid du Colombier return 0;
2697bb09086SDavid du Colombier }
2707bb09086SDavid du Colombier return 0; /* not reached */
2717bb09086SDavid du Colombier }
2727bb09086SDavid du Colombier
2737bb09086SDavid du Colombier static void
unimp(ulong pc,ulong op)2747bb09086SDavid du Colombier unimp(ulong pc, ulong op)
2757bb09086SDavid du Colombier {
2767bb09086SDavid du Colombier char buf[60];
2777bb09086SDavid du Colombier
2787bb09086SDavid du Colombier snprint(buf, sizeof(buf), "sys: fp: pc=%lux unimp fp 0x%.8lux", pc, op);
2797bb09086SDavid du Colombier if(fpemudebug)
2807bb09086SDavid du Colombier print("FPE: %s\n", buf);
2817bb09086SDavid du Colombier error(buf);
2827bb09086SDavid du Colombier /* no return */
2837bb09086SDavid du Colombier }
2847bb09086SDavid du Colombier
2857bb09086SDavid du Colombier static void
fpemu(ulong pc,ulong op,Ureg * ur,FPsave * ufp)2867bb09086SDavid du Colombier fpemu(ulong pc, ulong op, Ureg *ur, FPsave *ufp)
2877bb09086SDavid du Colombier {
2887bb09086SDavid du Colombier int rn, rd, tag, o;
2897bb09086SDavid du Colombier long off;
2907bb09086SDavid du Colombier ulong ea;
2917bb09086SDavid du Colombier Internal tmp, *fm, *fn;
2927bb09086SDavid du Colombier
2937bb09086SDavid du Colombier /* note: would update fault status here if we noted numeric exceptions */
2947bb09086SDavid du Colombier
2957bb09086SDavid du Colombier /*
2967bb09086SDavid du Colombier * LDF, STF; 10.1.1
2977bb09086SDavid du Colombier */
2987bb09086SDavid du Colombier if(((op>>25)&7) == 6){
2997bb09086SDavid du Colombier if(op & (1<<22))
3007bb09086SDavid du Colombier unimp(pc, op); /* packed or extended */
3017bb09086SDavid du Colombier rn = (op>>16)&0xF;
3027bb09086SDavid du Colombier off = (op&0xFF)<<2;
3037bb09086SDavid du Colombier if((op & (1<<23)) == 0)
3047bb09086SDavid du Colombier off = -off;
3057bb09086SDavid du Colombier ea = REG(ur, rn);
3067bb09086SDavid du Colombier if(rn == REGPC)
3077bb09086SDavid du Colombier ea += 8;
3087bb09086SDavid du Colombier if(op & (1<<24))
3097bb09086SDavid du Colombier ea += off;
3107bb09086SDavid du Colombier rd = (op>>12)&7;
3117bb09086SDavid du Colombier if(op & (1<<20)){
3127bb09086SDavid du Colombier if(op & (1<<15))
3137bb09086SDavid du Colombier fld(fpid2i, rd, ea, 8, ufp);
3147bb09086SDavid du Colombier else
3157bb09086SDavid du Colombier fld(fpis2i, rd, ea, 4, ufp);
3167bb09086SDavid du Colombier }else{
3177bb09086SDavid du Colombier if(op & (1<<15))
3187bb09086SDavid du Colombier fst(fpii2d, ea, rd, 8, ufp);
3197bb09086SDavid du Colombier else
3207bb09086SDavid du Colombier fst(fpii2s, ea, rd, 4, ufp);
3217bb09086SDavid du Colombier }
3227bb09086SDavid du Colombier if((op & (1<<24)) == 0)
3237bb09086SDavid du Colombier ea += off;
3247bb09086SDavid du Colombier if(op & (1<<21))
3257bb09086SDavid du Colombier REG(ur, rn) = ea;
3267bb09086SDavid du Colombier return;
3277bb09086SDavid du Colombier }
3287bb09086SDavid du Colombier
3297bb09086SDavid du Colombier /*
3307bb09086SDavid du Colombier * CPRT/transfer, 10.3
3317bb09086SDavid du Colombier */
3327bb09086SDavid du Colombier if(op & (1<<4)){
3337bb09086SDavid du Colombier rd = (op>>12) & 0xF;
3347bb09086SDavid du Colombier
3357bb09086SDavid du Colombier /*
3367bb09086SDavid du Colombier * compare, 10.3.1
3377bb09086SDavid du Colombier */
3387bb09086SDavid du Colombier if(rd == 15 && op & (1<<20)){
3397bb09086SDavid du Colombier rn = (op>>16)&7;
3407bb09086SDavid du Colombier fn = &FR(ufp, rn);
3417bb09086SDavid du Colombier if(op & (1<<3)){
3427bb09086SDavid du Colombier fm = &fpconst[op&7];
3437bb09086SDavid du Colombier if(fpemudebug)
3447bb09086SDavid du Colombier tag = 'C';
3457bb09086SDavid du Colombier }else{
3467bb09086SDavid du Colombier fm = &FR(ufp, op&7);
3477bb09086SDavid du Colombier if(fpemudebug)
3487bb09086SDavid du Colombier tag = 'F';
3497bb09086SDavid du Colombier }
3507bb09086SDavid du Colombier switch((op>>21)&7){
3517bb09086SDavid du Colombier default:
3527bb09086SDavid du Colombier unimp(pc, op);
3537bb09086SDavid du Colombier case 4: /* CMF: Fn :: Fm */
3547bb09086SDavid du Colombier case 6: /* CMFE: Fn :: Fm (with exception) */
3557bb09086SDavid du Colombier ur->psr &= ~(N|C|Z|V);
3567bb09086SDavid du Colombier ur->psr |= fcmp(fn, fm);
3577bb09086SDavid du Colombier break;
3587bb09086SDavid du Colombier case 5: /* CNF: Fn :: -Fm */
3597bb09086SDavid du Colombier case 7: /* CNFE: Fn :: -Fm (with exception) */
3607bb09086SDavid du Colombier tmp = *fm;
3617bb09086SDavid du Colombier tmp.s ^= 1;
3627bb09086SDavid du Colombier ur->psr &= ~(N|C|Z|V);
3637bb09086SDavid du Colombier ur->psr |= fcmp(fn, &tmp);
3647bb09086SDavid du Colombier break;
3657bb09086SDavid du Colombier }
3667bb09086SDavid du Colombier if(fpemudebug)
3677bb09086SDavid du Colombier print("CMPF %c%d,F%ld =%#lux\n",
3687bb09086SDavid du Colombier tag, rn, op&7, ur->psr>>28);
3697bb09086SDavid du Colombier return;
3707bb09086SDavid du Colombier }
3717bb09086SDavid du Colombier
3727bb09086SDavid du Colombier /*
3737bb09086SDavid du Colombier * other transfer, 10.3
3747bb09086SDavid du Colombier */
3757bb09086SDavid du Colombier switch((op>>20)&0xF){
3767bb09086SDavid du Colombier default:
3777bb09086SDavid du Colombier unimp(pc, op);
3787bb09086SDavid du Colombier case 0: /* FLT */
3797bb09086SDavid du Colombier rn = (op>>16) & 7;
3807bb09086SDavid du Colombier fpiw2i(&FR(ufp, rn), ®(ur, rd));
3817bb09086SDavid du Colombier if(fpemudebug)
3827bb09086SDavid du Colombier print("MOVW[FD] R%d, F%d\n", rd, rn);
3837bb09086SDavid du Colombier break;
3847bb09086SDavid du Colombier case 1: /* FIX */
3857bb09086SDavid du Colombier if(op & (1<<3))
3867bb09086SDavid du Colombier unimp(pc, op);
3877bb09086SDavid du Colombier rn = op & 7;
3887bb09086SDavid du Colombier tmp = FR(ufp, rn);
3897bb09086SDavid du Colombier fpii2w(®(ur, rd), &tmp);
3907bb09086SDavid du Colombier if(fpemudebug)
3917bb09086SDavid du Colombier print("MOV[FD]W F%d, R%d =%ld\n", rn, rd, REG(ur, rd));
3927bb09086SDavid du Colombier break;
3937bb09086SDavid du Colombier case 2: /* FPSR := Rd */
3947bb09086SDavid du Colombier ufp->status = REG(ur, rd);
3957bb09086SDavid du Colombier if(fpemudebug)
3967bb09086SDavid du Colombier print("MOVW R%d, FPSR\n", rd);
3977bb09086SDavid du Colombier break;
3987bb09086SDavid du Colombier case 3: /* Rd := FPSR */
3997bb09086SDavid du Colombier REG(ur, rd) = ufp->status;
4007bb09086SDavid du Colombier if(fpemudebug)
4017bb09086SDavid du Colombier print("MOVW FPSR, R%d\n", rd);
4027bb09086SDavid du Colombier break;
4037bb09086SDavid du Colombier case 4: /* FPCR := Rd */
4047bb09086SDavid du Colombier ufp->control = REG(ur, rd);
4057bb09086SDavid du Colombier if(fpemudebug)
4067bb09086SDavid du Colombier print("MOVW R%d, FPCR\n", rd);
4077bb09086SDavid du Colombier break;
4087bb09086SDavid du Colombier case 5: /* Rd := FPCR */
4097bb09086SDavid du Colombier REG(ur, rd) = ufp->control;
4107bb09086SDavid du Colombier if(fpemudebug)
4117bb09086SDavid du Colombier print("MOVW FPCR, R%d\n", rd);
4127bb09086SDavid du Colombier break;
4137bb09086SDavid du Colombier }
4147bb09086SDavid du Colombier return;
4157bb09086SDavid du Colombier }
4167bb09086SDavid du Colombier
4177bb09086SDavid du Colombier /*
4187bb09086SDavid du Colombier * arithmetic
4197bb09086SDavid du Colombier */
4207bb09086SDavid du Colombier
4217bb09086SDavid du Colombier if(op & (1<<3)){ /* constant */
4227bb09086SDavid du Colombier fm = &fpconst[op&7];
4237bb09086SDavid du Colombier if(fpemudebug)
4247bb09086SDavid du Colombier tag = 'C';
4257bb09086SDavid du Colombier }else{
4267bb09086SDavid du Colombier fm = &FR(ufp, op&7);
4277bb09086SDavid du Colombier if(fpemudebug)
4287bb09086SDavid du Colombier tag = 'F';
4297bb09086SDavid du Colombier }
4307bb09086SDavid du Colombier rd = (op>>12)&7;
4317bb09086SDavid du Colombier o = (op>>20)&0xF;
4327bb09086SDavid du Colombier if(op & (1<<15)){ /* monadic */
4337bb09086SDavid du Colombier FP1 *fp;
4347bb09086SDavid du Colombier fp = &optab1[o];
4357bb09086SDavid du Colombier if(fp->f == nil)
4367bb09086SDavid du Colombier unimp(pc, op);
4377bb09086SDavid du Colombier if(fpemudebug)
4387bb09086SDavid du Colombier print("%s %c%ld,F%d\n", fp->name, tag, op&7, rd);
4397bb09086SDavid du Colombier (*fp->f)(fm, &FR(ufp, rd));
4407bb09086SDavid du Colombier } else {
4417bb09086SDavid du Colombier FP2 *fp;
4427bb09086SDavid du Colombier fp = &optab2[o];
4437bb09086SDavid du Colombier if(fp->f == nil)
4447bb09086SDavid du Colombier unimp(pc, op);
4457bb09086SDavid du Colombier rn = (op>>16)&7;
4467bb09086SDavid du Colombier if(fpemudebug)
4477bb09086SDavid du Colombier print("%s %c%ld,F%d,F%d\n", fp->name, tag, op&7, rn, rd);
4487bb09086SDavid du Colombier (*fp->f)(*fm, FR(ufp, rn), &FR(ufp, rd));
4497bb09086SDavid du Colombier }
4507bb09086SDavid du Colombier }
4517bb09086SDavid du Colombier
4527bb09086SDavid du Colombier void
casemu(ulong pc,ulong op,Ureg * ur)4537bb09086SDavid du Colombier casemu(ulong pc, ulong op, Ureg *ur)
4547bb09086SDavid du Colombier {
4557bb09086SDavid du Colombier ulong *rp, ro, rn, *rd;
4567bb09086SDavid du Colombier
4577bb09086SDavid du Colombier USED(pc);
4587bb09086SDavid du Colombier
4597bb09086SDavid du Colombier rp = (ulong*)ur;
4607bb09086SDavid du Colombier ro = rp[op>>16 & 0x7];
4617bb09086SDavid du Colombier rn = rp[op>>0 & 0x7];
4627bb09086SDavid du Colombier rd = rp + (op>>12 & 0x7);
4637bb09086SDavid du Colombier rp = (ulong*)*rd;
4647bb09086SDavid du Colombier validaddr((ulong)rp, 4, 1);
4657bb09086SDavid du Colombier splhi();
4667bb09086SDavid du Colombier if(*rd = (*rp == ro))
4677bb09086SDavid du Colombier *rp = rn;
4687bb09086SDavid du Colombier spllo();
4697bb09086SDavid du Colombier }
4707bb09086SDavid du Colombier
4717bb09086SDavid du Colombier int ldrexvalid;
4727bb09086SDavid du Colombier
4737bb09086SDavid du Colombier void
ldrex(ulong pc,ulong op,Ureg * ur)4747bb09086SDavid du Colombier ldrex(ulong pc, ulong op, Ureg *ur)
4757bb09086SDavid du Colombier {
4767bb09086SDavid du Colombier ulong *rp, *rd, *addr;
4777bb09086SDavid du Colombier
4787bb09086SDavid du Colombier USED(pc);
4797bb09086SDavid du Colombier
4807bb09086SDavid du Colombier rp = (ulong*)ur;
4817bb09086SDavid du Colombier rd = rp + (op>>16 & 0x7);
4827bb09086SDavid du Colombier addr = (ulong*)*rd;
4837bb09086SDavid du Colombier validaddr((ulong)addr, 4, 0);
4847bb09086SDavid du Colombier ldrexvalid = 1;
4857bb09086SDavid du Colombier rp[op>>12 & 0x7] = *addr;
4867bb09086SDavid du Colombier if(fpemudebug)
4877bb09086SDavid du Colombier print("ldrex, r%ld = [r%ld]@0x%8.8p = 0x%8.8lux",
4887bb09086SDavid du Colombier op>>12 & 0x7, op>>16 & 0x7, addr, rp[op>>12 & 0x7]);
4897bb09086SDavid du Colombier }
4907bb09086SDavid du Colombier
4917bb09086SDavid du Colombier void
clrex(ulong,ulong,Ureg *)4920f53e541SDavid du Colombier clrex(ulong, ulong, Ureg *)
4930f53e541SDavid du Colombier {
4940f53e541SDavid du Colombier ldrexvalid = 0;
4950f53e541SDavid du Colombier if(fpemudebug)
4960f53e541SDavid du Colombier print("clrex");
4970f53e541SDavid du Colombier }
4980f53e541SDavid du Colombier
4990f53e541SDavid du Colombier void
strex(ulong pc,ulong op,Ureg * ur)5007bb09086SDavid du Colombier strex(ulong pc, ulong op, Ureg *ur)
5017bb09086SDavid du Colombier {
5027bb09086SDavid du Colombier ulong *rp, rn, *rd, *addr;
5037bb09086SDavid du Colombier
5047bb09086SDavid du Colombier USED(pc);
5057bb09086SDavid du Colombier
5067bb09086SDavid du Colombier rp = (ulong*)ur;
5077bb09086SDavid du Colombier rd = rp + (op>>16 & 0x7);
5087bb09086SDavid du Colombier rn = rp[op>>0 & 0x7];
5097bb09086SDavid du Colombier addr = (ulong*)*rd;
5107bb09086SDavid du Colombier validaddr((ulong)addr, 4, 1);
5117bb09086SDavid du Colombier splhi();
5127bb09086SDavid du Colombier if(ldrexvalid){
5137bb09086SDavid du Colombier if(fpemudebug)
5147bb09086SDavid du Colombier print("strex valid, [r%ld]@0x%8.8p = r%ld = 0x%8.8lux",
5157bb09086SDavid du Colombier op>>16 & 0x7, addr, op>>0 & 0x7, rn);
5167bb09086SDavid du Colombier *addr = rn;
5177bb09086SDavid du Colombier ldrexvalid = 0;
5187bb09086SDavid du Colombier rp[op>>12 & 0x7] = 0;
5197bb09086SDavid du Colombier }else{
5207bb09086SDavid du Colombier if(fpemudebug)
5217bb09086SDavid du Colombier print("strex invalid, r%ld = 1", op>>16 & 0x7);
5227bb09086SDavid du Colombier rp[op>>12 & 0x7] = 1;
5237bb09086SDavid du Colombier }
5247bb09086SDavid du Colombier spllo();
5257bb09086SDavid du Colombier }
5267bb09086SDavid du Colombier
5277bb09086SDavid du Colombier struct {
5287bb09086SDavid du Colombier ulong opc;
5297bb09086SDavid du Colombier ulong mask;
5307bb09086SDavid du Colombier void (*f)(ulong, ulong, Ureg*);
5317bb09086SDavid du Colombier } specialopc[] = {
5327bb09086SDavid du Colombier { 0x01900f9f, 0x0ff00fff, ldrex },
5337bb09086SDavid du Colombier { 0x01800f90, 0x0ff00ff0, strex },
5340f53e541SDavid du Colombier { 0xf57ff01f, 0xffffffff, clrex },
5357bb09086SDavid du Colombier { 0x0ed00100, 0x0ef08100, casemu },
5367bb09086SDavid du Colombier { 0x00000000, 0x00000000, nil }
5377bb09086SDavid du Colombier };
5387bb09086SDavid du Colombier
5397bb09086SDavid du Colombier /*
5407bb09086SDavid du Colombier * returns the number of FP instructions emulated
5417bb09086SDavid du Colombier */
5427bb09086SDavid du Colombier int
fpiarm(Ureg * ur)5437bb09086SDavid du Colombier fpiarm(Ureg *ur)
5447bb09086SDavid du Colombier {
5457bb09086SDavid du Colombier ulong op, o;
5467bb09086SDavid du Colombier FPsave *ufp;
5477bb09086SDavid du Colombier int i, n;
5487bb09086SDavid du Colombier
5497bb09086SDavid du Colombier if(up == nil)
5507bb09086SDavid du Colombier panic("fpiarm not in a process");
5517bb09086SDavid du Colombier ufp = &up->fpsave;
5527bb09086SDavid du Colombier /* because all the state is in the proc structure,
5537bb09086SDavid du Colombier * it need not be saved/restored
5547bb09086SDavid du Colombier */
5557bb09086SDavid du Colombier if(up->fpstate != FPactive){
5567bb09086SDavid du Colombier // assert(sizeof(Internal) == sizeof(ufp->regs[0]));
5577bb09086SDavid du Colombier up->fpstate = FPactive;
5587bb09086SDavid du Colombier ufp->control = 0;
5597bb09086SDavid du Colombier ufp->status = (0x01<<28)|(1<<12); /* software emulation, alternative C flag */
5607bb09086SDavid du Colombier for(n = 0; n < 8; n++)
5617bb09086SDavid du Colombier FR(ufp, n) = fpconst[0];
5627bb09086SDavid du Colombier }
5637bb09086SDavid du Colombier for(n=0; ;n++){
5647bb09086SDavid du Colombier validaddr(ur->pc, 4, 0);
5657bb09086SDavid du Colombier op = *(ulong*)(ur->pc);
5667bb09086SDavid du Colombier if(fpemudebug)
5677bb09086SDavid du Colombier print("%#lux: %#8.8lux ", ur->pc, op);
5687bb09086SDavid du Colombier o = (op>>24) & 0xF;
5697bb09086SDavid du Colombier if(condok(ur->psr, op>>28)){
5707bb09086SDavid du Colombier for(i = 0; specialopc[i].f; i++)
5717bb09086SDavid du Colombier if((op & specialopc[i].mask) == specialopc[i].opc)
5727bb09086SDavid du Colombier break;
5737bb09086SDavid du Colombier if(specialopc[i].f)
5747bb09086SDavid du Colombier specialopc[i].f(ur->pc, op, ur);
5757bb09086SDavid du Colombier else if((op & 0xF00) != 0x100 || o != 0xE && (o&~1) != 0xC)
5767bb09086SDavid du Colombier break;
5777bb09086SDavid du Colombier else
5787bb09086SDavid du Colombier fpemu(ur->pc, op, ur, ufp);
5797bb09086SDavid du Colombier }else if((op & 0xF00) != 0x100 || o != 0xE && (o&~1) != 0xC)
5807bb09086SDavid du Colombier break;
5817bb09086SDavid du Colombier ur->pc += 4;
5827bb09086SDavid du Colombier }
5837bb09086SDavid du Colombier if(fpemudebug) print("\n");
5847bb09086SDavid du Colombier return n;
5857bb09086SDavid du Colombier }
586