vfp floating point emulation for the kw kernel. jitten pathy did the work on decoding the instructions. Reference: /n/atom/patch/applied2013/kw-vfp Date: Sat Jun 15 02:57:16 CES 2013 Signed-off-by: quanstro@quanstro.net --- /sys/src/9/kw/plug Sat Jun 15 02:57:05 2013 +++ /sys/src/9/kw/plug Sat Jun 15 02:57:05 2013 @@ -35,7 +35,6 @@ usb link -# etherkw ethermii ether1116 ethermii archkw ethermedium @@ -55,6 +54,9 @@ ipmux misc + fpivfp fpi fpimem +# fpiarm fpi fpimem + rdb coproc sdaoe --- /sys/src/9/kw/mkfile Sat Jun 15 02:57:05 2013 +++ /sys/src/9/kw/mkfile Sat Jun 15 02:57:05 2013 @@ -49,9 +49,6 @@ arch.$O\ cga.$O\ clock.$O\ - fpi.$O\ - fpiarm.$O\ - fpimem.$O\ main.$O\ mmu.$O\ random.$O\ --- /sys/src/9/kw/fpiarm.c Sat Jun 15 02:57:05 2013 +++ /sys/src/9/kw/fpiarm.c Sat Jun 15 02:57:05 2013 @@ -549,7 +549,8 @@ 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){ --- /sys/src/9/kw/fpivfp.c Thu Jan 1 00:00:00 1970 +++ /sys/src/9/kw/fpivfp.c Sat Jun 15 02:57:05 2013 @@ -0,0 +1,783 @@ +/* + * this doesn't attempt to implement ARM floating-point properties + * that aren't visible in the Inferno environment. + * all arithmetic is done in double precision. + * the FP trap status isn't updated. + */ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" + +#include "ureg.h" + +#include "arm.h" +#include "../port/fpi.h" + +#define Nfpregs 16 + +/* 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)&(Nfpregs - 1)]) + +typedef struct FP2 FP2; +typedef struct FP1 FP1; + +struct FP2 { + char* name; + void (*f)(Internal, Internal, Internal*); +}; + +struct FP1 { + char* name; + void (*f)(Internal*, Internal*); +}; + +enum { + N = 1<<31, + Z = 1<<30, + C = 1<<29, + V = 1<<28, + REGPC = 15, +}; + +enum { + fpemudebug = 0, +}; + +#undef OFR +#define OFR(X) ((ulong)&((Ureg*)0)->X) + +static int roff[] = { + OFR(r0), OFR(r1), OFR(r2), OFR(r3), + OFR(r4), OFR(r5), OFR(r6), OFR(r7), + OFR(r8), OFR(r9), OFR(r10), OFR(r11), + OFR(r12), OFR(r13), OFR(r14), OFR(pc), +}; + +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 */ + {0, 0x400, 0x00000000, 0x08000000}, /* 2.0 */ + {0, 0x400, 0x00000000, 0x0C000000}, /* 3.0 */ + {0, 0x401, 0x00000000, 0x08000000}, /* 4.0 */ + {0, 0x401, 0x00000000, 0x0A000000}, /* 5.0 */ + {0, 0x3FE, 0x00000000, 0x08000000}, /* 0.5 */ + {0, 0x402, 0x00000000, 0x0A000000}, /* 10.0 */ +}; + +/* + * arm binary operations + */ + +static void +fadd(Internal m, Internal n, Internal *d) +{ + (m.s == n.s? fpiadd: fpisub)(&m, &n, d); +} + +static void +fsub(Internal m, Internal n, Internal *d) +{ + m.s ^= 1; + (m.s == n.s? fpiadd: fpisub)(&m, &n, d); +} + +static void +fsubr(Internal m, Internal n, Internal *d) +{ + n.s ^= 1; + (n.s == m.s? fpiadd: fpisub)(&n, &m, d); +} + +static void +fmul(Internal m, Internal n, Internal *d) +{ + fpimul(&m, &n, d); +} + +static void +fdiv(Internal m, Internal n, Internal *d) +{ + fpidiv(&m, &n, d); +} + +static void +fdivr(Internal m, Internal n, Internal *d) +{ + fpidiv(&n, &m, d); +} + +/* + * arm unary operations + */ + +static void +fmov(Internal *m, Internal *d) +{ + *d = *m; +} + +static void +fmovn(Internal *m, Internal *d) +{ + *d = *m; + d->s ^= 1; +} + +static void +fabsf(Internal *m, Internal *d) +{ + *d = *m; + d->s = 0; +} + +static void +frnd(Internal *m, Internal *d) +{ + short e; + + (m->s? fsub: fadd)(fpconst[6], *m, d); + if(IsWeird(d)) + return; + fpiround(d); + e = (d->e - ExpBias) + 1; + if(e <= 0) + SetZero(d); + else if(e > FractBits){ + if(e < 2*FractBits) + d->l &= ~((1<<(2*FractBits - e))-1); + }else{ + d->l = 0; + if(e < FractBits) + d->h &= ~((1<<(FractBits-e))-1); + } +} + +/* + * ARM 7500 FPA opcodes + */ + +static FP1 optab1[16] = { /* Fd := OP Fm */ +[0] {"MOVF", fmov}, +[1] {"NEGF", fmovn}, +[2] {"ABSF", fabsf}, +[3] {"RNDF", frnd}, +[4] {"SQTF", /*fsqt*/0}, +/* LOG, LGN, EXP, SIN, COS, TAN, ASN, ACS, ATN all `deprecated' */ +/* URD and NRM aren't implemented */ +}; + +static FP2 optab2[16] = { /* Fd := Fn OP Fm */ +[0] {"ADDF", fadd}, +[1] {"MULF", fmul}, +[2] {"SUBF", fsub}, +[3] {"RSUBF", fsubr}, +[4] {"DIVF", fdiv}, +[5] {"RDIVF", fdivr}, +/* POW, RPW deprecated */ +[8] {"REMF", /*frem*/0}, +[9] {"FMF", fmul}, /* fast multiply */ +[10] {"FDV", fdiv}, /* fast divide */ +[11] {"FRD", fdivr}, /* fast reverse divide */ +/* 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) +{ + int i; + Internal rm, rn; + + if(IsWeird(m) || IsWeird(n)){ + /* BUG: should trap if not masked */ + return V|C; + } + rn = *n; + rm = *m; + fpiround(&rn); + fpiround(&rm); + i = fpicmp(&rn, &rm); + if(i > 0) + return C; + else if(i == 0) + return C|Z; + else + return N; +} + +static void +fld(void (*f)(Internal*, void*), int d, ulong ea, int n, FPsave *ufp) +{ + void *mem; + + mem = (void*)ea; + (*f)(&FR(ufp, d), mem); + if(fpemudebug) + print("MOV%c #%lux, F%d\n", n==8? 'D': 'F', ea, d); +} + +static void +fst(void (*f)(void*, Internal*), ulong ea, int s, int n, FPsave *ufp) +{ + Internal tmp; + void *mem; + + mem = (void*)ea; + tmp = FR(ufp, s); + if(fpemudebug) + print("MOV%c F%d,#%lux\n", n==8? 'D': 'F', s, ea); + (*f)(mem, &tmp); +} + +static int +condok(int cc, int c) +{ + switch(c){ + case 0: /* Z set */ + return cc&Z; + case 1: /* Z clear */ + return (cc&Z) == 0; + case 2: /* C set */ + return cc&C; + case 3: /* C clear */ + return (cc&C) == 0; + case 4: /* N set */ + return cc&N; + case 5: /* N clear */ + return (cc&N) == 0; + case 6: /* V set */ + return cc&V; + case 7: /* V clear */ + return (cc&V) == 0; + case 8: /* C set and Z clear */ + return cc&C && (cc&Z) == 0; + case 9: /* C clear or Z set */ + return (cc&C) == 0 || cc&Z; + case 10: /* N set and V set, or N clear and V clear */ + return (~cc&(N|V))==0 || (cc&(N|V)) == 0; + case 11: /* N set and V clear, or N clear and V set */ + return (cc&(N|V))==N || (cc&(N|V))==V; + case 12: /* Z clear, and either N set and V set or N clear and V clear */ + return (cc&Z) == 0 && ((~cc&(N|V))==0 || (cc&(N|V))==0); + case 13: /* Z set, or N set and V clear or N clear and V set */ + return (cc&Z) || (cc&(N|V))==N || (cc&(N|V))==V; + case 14: /* always */ + return 1; + case 15: /* never (reserved) */ + return 0; + } + return 0; /* not reached */ +} + +static void +unimp(ulong pc, ulong op) +{ + char buf[60]; + + snprint(buf, sizeof(buf), "sys: fp: pc=%lux unimp fp 0x%.8lux", pc, op); + if(fpemudebug) + print("FPE: %s\n", buf); + error(buf); + /* no return */ +} + +static void +fpaemu(ulong pc, ulong op, Ureg *ur, FPsave *ufp) +{ + int rn, rd, tag, o; + long off; + ulong ea; + Internal tmp, *fm, *fn; + + /* note: would update fault status here if we noted numeric exceptions */ + + /* + * LDF, STF; 10.1.1 + */ + if(((op>>25)&7) == 6){ + if(op & (1<<22)) + unimp(pc, op); /* packed or extended */ + rn = (op>>16)&0xF; + off = (op&0xFF)<<2; + if((op & (1<<23)) == 0) + off = -off; + ea = REG(ur, rn); + if(rn == REGPC) + ea += 8; + if(op & (1<<24)) + ea += off; + rd = (op>>12)&7; + if(op & (1<<20)){ + if(op & (1<<15)) + fld(fpid2i, rd, ea, 8, ufp); + else + fld(fpis2i, rd, ea, 4, ufp); + }else{ + if(op & (1<<15)) + fst(fpii2d, ea, rd, 8, ufp); + else + fst(fpii2s, ea, rd, 4, ufp); + } + if((op & (1<<24)) == 0) + ea += off; + if(op & (1<<21)) + REG(ur, rn) = ea; + return; + } + + /* + * CPRT/transfer, 10.3 + */ + if(op & (1<<4)){ + rd = (op>>12) & 0xF; + + /* + * compare, 10.3.1 + */ + if(rd == 15 && op & (1<<20)){ + rn = (op>>16)&7; + fn = &FR(ufp, rn); + if(op & (1<<3)){ + fm = &fpconst[op&7]; + if(fpemudebug) + tag = 'C'; + }else{ + fm = &FR(ufp, op&7); + if(fpemudebug) + tag = 'F'; + } + switch((op>>21)&7){ + default: + unimp(pc, op); + case 4: /* CMF: Fn :: Fm */ + case 6: /* CMFE: Fn :: Fm (with exception) */ + ur->psr &= ~(N|C|Z|V); + ur->psr |= fcmp(fn, fm); + break; + case 5: /* CNF: Fn :: -Fm */ + case 7: /* CNFE: Fn :: -Fm (with exception) */ + tmp = *fm; + tmp.s ^= 1; + ur->psr &= ~(N|C|Z|V); + ur->psr |= fcmp(fn, &tmp); + break; + } + if(fpemudebug) + print("CMPF %c%d,F%ld =%#lux\n", + tag, rn, op&7, ur->psr>>28); + return; + } + + /* + * other transfer, 10.3 + */ + switch((op>>20)&0xF){ + default: + unimp(pc, op); + case 0: /* FLT */ + rn = (op>>16) & 7; + fpiw2i(&FR(ufp, rn), ®(ur, rd)); + if(fpemudebug) + print("MOVW[FD] R%d, F%d\n", rd, rn); + break; + case 1: /* FIX */ + if(op & (1<<3)) + unimp(pc, op); + rn = op & 7; + tmp = FR(ufp, rn); + fpii2w(®(ur, rd), &tmp); + if(fpemudebug) + print("MOV[FD]W F%d, R%d =%ld\n", rn, rd, REG(ur, rd)); + break; + case 2: /* FPSR := Rd */ + ufp->status = REG(ur, rd); + if(fpemudebug) + print("MOVW R%d, FPSR\n", rd); + break; + case 3: /* Rd := FPSR */ + REG(ur, rd) = ufp->status; + if(fpemudebug) + print("MOVW FPSR, R%d\n", rd); + break; + case 4: /* FPCR := Rd */ + ufp->control = REG(ur, rd); + if(fpemudebug) + print("MOVW R%d, FPCR\n", rd); + break; + case 5: /* Rd := FPCR */ + REG(ur, rd) = ufp->control; + if(fpemudebug) + print("MOVW FPCR, R%d\n", rd); + break; + } + return; + } + + /* + * arithmetic + */ + + if(op & (1<<3)){ /* constant */ + fm = &fpconst[op&7]; + if(fpemudebug) + tag = 'C'; + }else{ + fm = &FR(ufp, op&7); + if(fpemudebug) + tag = 'F'; + } + rd = (op>>12)&7; + o = (op>>20)&0xF; + if(op & (1<<15)){ /* monadic */ + FP1 *fp; + fp = &optab1[o]; + if(fp->f == nil) + unimp(pc, op); + if(fpemudebug) + print("%s %c%ld,F%d\n", fp->name, tag, op&7, rd); + (*fp->f)(fm, &FR(ufp, rd)); + } else { + FP2 *fp; + fp = &optab2[o]; + if(fp->f == nil) + unimp(pc, op); + rn = (op>>16)&7; + if(fpemudebug) + print("%s %c%ld,F%d,F%d\n", fp->name, tag, op&7, rn, rd); + (*fp->f)(*fm, FR(ufp, rn), &FR(ufp, rd)); + } +} + +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) +{ + ulong *rp, ro, rn, *rd; + + USED(pc); + + rp = (ulong*)ur; + ro = rp[op>>16 & 0x7]; + rn = rp[op>>0 & 0x7]; + rd = rp + (op>>12 & 0x7); + rp = (ulong*)*rd; + validaddr((ulong)rp, 4, 1); + splhi(); + if(*rd = (*rp == ro)) + *rp = rn; + spllo(); +} + +int ldrexvalid; + +void +ldrex(ulong pc, ulong op, Ureg *ur) +{ + ulong *rp, *rd, *addr; + + USED(pc); + + rp = (ulong*)ur; + rd = rp + (op>>16 & 0x7); + addr = (ulong*)*rd; + validaddr((ulong)addr, 4, 0); + ldrexvalid = 1; + rp[op>>12 & 0x7] = *addr; + if(fpemudebug) + print("ldrex, r%ld = [r%ld]@0x%8.8p = 0x%8.8lux", + op>>12 & 0x7, op>>16 & 0x7, addr, rp[op>>12 & 0x7]); +} + +void +clrex(ulong, ulong, Ureg *) +{ + ldrexvalid = 0; + if(fpemudebug) + print("clrex"); +} + +void +strex(ulong pc, ulong op, Ureg *ur) +{ + ulong *rp, rn, *rd, *addr; + + USED(pc); + + rp = (ulong*)ur; + rd = rp + (op>>16 & 0x7); + rn = rp[op>>0 & 0x7]; + addr = (ulong*)*rd; + validaddr((ulong)addr, 4, 1); + splhi(); + if(ldrexvalid){ + if(fpemudebug) + print("strex valid, [r%ld]@0x%8.8p = r%ld = 0x%8.8lux", + op>>16 & 0x7, addr, op>>0 & 0x7, rn); + *addr = rn; + ldrexvalid = 0; + rp[op>>12 & 0x7] = 0; + }else{ + if(fpemudebug) + print("strex invalid, r%ld = 1", op>>16 & 0x7); + rp[op>>12 & 0x7] = 1; + } + spllo(); +} + +struct { + ulong opc; + ulong mask; + void (*f)(ulong, ulong, Ureg*); +} specialopc[] = { + { 0x01900f9f, 0x0ff00fff, ldrex }, + { 0x01800f90, 0x0ff00ff0, strex }, + { 0xf57ff01f, 0xffffffff, clrex }, + { 0x0ed00100, 0x0ef08100, casemu }, + { 0x00000000, 0x00000000, nil } +}; + + +/* + * returns the number of FP instructions emulated + */ +int +fpiarm(Ureg *ur) +{ + ulong op, o, cp; + FPsave *ufp; + int i, n; + + if(up == nil) + panic("fpiarm not in a process"); + ufp = &up->fpsave; + /* + * because all the emulated fp state is in the proc structure, + * it need not be saved/restored + */ + switch(up->fpstate){ + case FPactive: + case FPinactive: + error("illegal instruction: emulated fpu opcode in VFP mode"); + case FPinit: + assert(sizeof(Internal) <= sizeof(ufp->regs[0])); + up->fpstate = FPemu; + ufp->control = 0; + ufp->status = (0x01<<28)|(1<<12); /* sw emulation, alt. C flag */ + for(n = 0; n < Nfpregs; n++) + FR(ufp, n) = fpconst[0]; + } + for(n=0; ;n++){ + validaddr(ur->pc, 4, 0); + op = *(ulong*)(ur->pc); + if(fpemudebug) + print("%#lux: %#8.8lux ", ur->pc, op); + o = (op>>24) & 0xF; + cp = (op>>8) & 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 != nil) + specialopc[i].f(ur->pc, op, ur); + else if(ISFPAOP(cp, o)) + fpaemu(ur->pc, op, ur, ufp); + else if(ISVFPOP(cp, o)) + vfpemu(ur->pc, op, ur, ufp); + else + break; + } + ur->pc += 4; /* pretend cpu executed the instr */ + } + if(fpemudebug) + print("\n"); + return n; +} --- /sys/src/9/kw/dat.h Sat Jun 15 02:57:05 2013 +++ /sys/src/9/kw/dat.h Sat Jun 15 02:57:05 2013 @@ -65,6 +65,7 @@ { FPinit, FPactive, + FPemu, FPinactive, }; --- /sys/src/9/kw/arm.h Sat Jun 15 02:57:05 2013 +++ /sys/src/9/kw/arm.h Sat Jun 15 02:57:05 2013 @@ -4,10 +4,11 @@ #define PsrMusr 0x00000010 /* mode */ #define PsrMfiq 0x00000011 #define PsrMirq 0x00000012 -#define PsrMsvc 0x00000013 +#define PsrMsvc 0x00000013 /* `protected mode for OS' */ +#define PsrMmon 0x00000016 /* `secure monitor' (trustzone hyper) */ #define PsrMabt 0x00000017 #define PsrMund 0x0000001B -#define PsrMsys 0x0000001F +#define PsrMsys 0x0000001F /* `privileged user mode for OS' (trustzone) */ #define PsrMask 0x0000001F #define PsrDfiq 0x00000040 /* disable FIQ interrupts */ @@ -18,9 +19,15 @@ #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 */ @@ -36,26 +43,50 @@ */ #define CpID 0 /* ID and cache type */ #define CpCONTROL 1 /* miscellaneous control */ -#define CpTTB 2 /* Translation Table Base */ +#define CpTTB 2 /* Translation Table Base(s) */ #define CpDAC 3 /* Domain Access Control */ #define CpFSR 5 /* Fault Status */ #define CpFAR 6 /* Fault Address */ #define CpCACHE 7 /* cache/write buffer control */ #define CpTLB 8 /* TLB control */ -#define CpCLD 9 /* Cache Lockdown */ -#define CpTLD 10 /* TLB Lockdown */ +#define CpCLD 9 /* L2 Cache Lockdown, op1==1 */ +#define CpTLD 10 /* TLB Lockdown, with op2 */ +#define CpVECS 12 /* vector bases, op1==0, Crm==0, op2s (cortex) */ #define CpPID 13 /* Process ID */ #define CpTESTCFG 15 /* test config. (arm926) */ +#define CpSPM 15 /* system performance monitor (arm1176) */ + + +/* + * CpTTB op1==0, Crm==0 opcode2 values. + */ +#define CpTTB0 0 +#define CpTTB1 1 /* cortex */ +#define CpTTBctl 2 /* cortex */ + +/* + * CpFSR opcode2 values. + */ +#define CpFSRdata 0 /* armv6, armv7 */ +#define CpFSRinst 1 /* armv6, armv7 */ /* * CpID Secondary (CRm) registers. */ #define CpIDidct 0 + /* * CpID op1==0 opcode2 fields. + * the cortex has more op1 codes for cache size, etc. */ #define CpIDid 0 /* main ID */ #define CpIDct 1 /* cache type */ +#define CpIDtlb 3 /* tlb type (cortex) */ +#define CpIDmpid 5 /* multiprocessor id (cortex) */ + +/* CpIDid op1 values */ +#define CpIDcsize 1 /* cache size (cortex) */ +#define CpIDcssel 2 /* cache size select (cortex) */ /* * CpCONTROL @@ -191,4 +222,4 @@ #define L2AP(ap) (AP(3, (ap))|AP(2, (ap))|AP(1, (ap))|AP(0, (ap))) /* pre-armv7 */ #define DAC(n, v) F((v), (n)*2, 2) -#define HVECTORS 0xffff0000 /* addr of vectors */ +#define HVECTORS 0xffff0000