diff options
Diffstat (limited to 'utils')
| -rw-r--r-- | utils/5c/5.out.h | 2 | ||||
| -rw-r--r-- | utils/mkfile | 6 | ||||
| -rw-r--r-- | utils/tc/5.out.h | 5 | ||||
| -rw-r--r-- | utils/tl/asm.c | 22 | ||||
| -rw-r--r-- | utils/tl/l.h | 9 | ||||
| -rw-r--r-- | utils/tl/noop.c | 227 | ||||
| -rw-r--r-- | utils/tl/obj.c | 4 | ||||
| -rw-r--r-- | utils/tl/pass.c | 4 | ||||
| -rw-r--r-- | utils/tl/span.c | 8 | ||||
| -rw-r--r-- | utils/tl/thumb.c | 551 |
10 files changed, 574 insertions, 264 deletions
diff --git a/utils/5c/5.out.h b/utils/5c/5.out.h index a618f8f1..667456e0 100644 --- a/utils/5c/5.out.h +++ b/utils/5c/5.out.h @@ -25,7 +25,7 @@ #define NFREG 8 #define FREGRET 0 #define FREGEXT 7 -#define FREGTMP 15 +#define FREGTMP 7 /* compiler allocates register variables F0 up */ /* compiler allocates external registers F7 down */ diff --git a/utils/mkfile b/utils/mkfile index 804215b3..e6ee371a 100644 --- a/utils/mkfile +++ b/utils/mkfile @@ -54,6 +54,9 @@ NOTPLAN9=\ md5sum\ mkext\ ndate\ + ta\ + tc\ + tl\ # # Utils we build on Nt, for build environment compatibility. @@ -76,9 +79,6 @@ NTONLY=\ # Thumb-1 # OBSOLETE=\ - ta\ - tc\ - tl\ all:QV: all-$TARGMODEL clean:QV: clean-$TARGMODEL diff --git a/utils/tc/5.out.h b/utils/tc/5.out.h index 59aebab6..7a35f1c2 100644 --- a/utils/tc/5.out.h +++ b/utils/tc/5.out.h @@ -18,10 +18,11 @@ #define REGSP 13 #define REGLINK 14 #define REGPC 15 - -#define NFREG 8 + +#define NFREG 8 /* number of double precision registers */ #define FREGRET 0 #define FREGEXT 7 +#define FREGTMP 7 /* compiler allocates register variables F0 up */ /* compiler allocates external registers F7 down */ diff --git a/utils/tl/asm.c b/utils/tl/asm.c index 66a7f0c6..ec0f63a8 100644 --- a/utils/tl/asm.c +++ b/utils/tl/asm.c @@ -63,17 +63,15 @@ asmb(void) asmout(p, o); pc += o->size; } - while(pc-INITTEXT < textsize) { - cput(0); - pc++; + + /* output strings in text segment */ + while (pc < INITRODAT) { + cput(0); pc++; } - if(debug['a']) - Bprint(&bso, "\n"); Bflush(&bso); cflush(); - /* output strings in text segment */ etext = INITTEXT + textsize; for(t = pc; t < etext; t += sizeof(buf)-100) { if(etext-t > sizeof(buf)-100) @@ -82,6 +80,18 @@ asmb(void) datblk(t, etext-t, 1); } + pc = t; + + while(pc-INITTEXT < textsize) { + cput(0); + pc++; + } + + if(debug['a']) + Bprint(&bso, "\n"); + Bflush(&bso); + cflush(); + curtext = P; switch(HEADTYPE) { case 0: diff --git a/utils/tl/l.h b/utils/tl/l.h index 72e6ed28..3e84ff66 100644 --- a/utils/tl/l.h +++ b/utils/tl/l.h @@ -90,6 +90,7 @@ struct Sym uchar fnptr; // used as fn ptr Use* use; Sym* link; + long base; }; #define SIGNINTERN (1729*325*1729) @@ -248,6 +249,7 @@ EXTERN union EXTERN long HEADR; /* length of header */ EXTERN int HEADTYPE; /* type of header */ EXTERN long INITDAT; /* data location */ +EXTERN long INITRODAT; /* read-only data location */ EXTERN long INITRND; /* data round above text location */ EXTERN long INITTEXT; /* text location */ EXTERN char* INITENTRY; /* entry point */ @@ -322,12 +324,6 @@ void addpool(Prog*, Adr*); EXTERN Prog* blitrl; EXTERN Prog* elitrl; -void initdiv(void); -EXTERN Prog* prog_div; -EXTERN Prog* prog_divu; -EXTERN Prog* prog_mod; -EXTERN Prog* prog_modu; - #pragma varargck type "A" int #pragma varargck type "C" int #pragma varargck type "D" Adr* @@ -365,7 +361,6 @@ int compound(Prog*); double cputime(void); void datblk(long, long, int); void diag(char*, ...); -void divsig(void); void dodata(void); void doprof1(void); void doprof2(void); diff --git a/utils/tl/noop.c b/utils/tl/noop.c index 08ef6dbe..d849923c 100644 --- a/utils/tl/noop.c +++ b/utils/tl/noop.c @@ -125,18 +125,6 @@ noops(void) curbecome = p->from.offset; break; - case ADIV: - case ADIVU: - case AMOD: - case AMODU: - q = p; - if(prog_div == P) - initdiv(); - if(curtext != P) - curtext->mark &= ~LEAF; - setdiv(p->as); - continue; - case ANOP: q1 = p->link; q->link = q1; /* q is non-nop */ @@ -528,122 +516,6 @@ noops(void) break; - case ADIV: - case ADIVU: - case AMOD: - case AMODU: - if(debug['M']) - break; - if(p->from.type != D_REG) - break; - if(p->to.type != D_REG) - break; - q1 = p; - - /* MOV a,4(SP) */ - q = prg(); - q->link = p->link; - p->link = q; - p = q; - - p->as = AMOVW; - p->line = q1->line; - p->from.type = D_REG; - p->from.reg = q1->from.reg; - p->to.type = D_OREG; - p->to.reg = REGSP; - p->to.offset = 4; - - /* MOV b,REGTMP */ - q = prg(); - q->link = p->link; - p->link = q; - p = q; - - p->as = AMOVW; - p->line = q1->line; - p->from.type = D_REG; - p->from.reg = q1->reg; - if(q1->reg == NREG) - p->from.reg = q1->to.reg; - p->to.type = D_REG; - p->to.reg = prog_div != UP && prog_div->from.sym->thumb ? REGTMPT : REGTMP; - p->to.offset = 0; - - /* CALL appropriate */ - q = prg(); - q->link = p->link; - p->link = q; - p = q; - -#ifdef CALLEEBX - p->as = ABL; -#else - if(prog_div != UP && prog_div->from.sym->thumb) - p->as = thumb ? ABL : ABX; - else - p->as = thumb ? ABX : ABL; -#endif - p->line = q1->line; - p->to.type = D_BRANCH; - p->cond = p; - switch(o) { - case ADIV: - p->cond = prog_div; - p->to.sym = sym_div; - break; - case ADIVU: - p->cond = prog_divu; - p->to.sym = sym_divu; - break; - case AMOD: - p->cond = prog_mod; - p->to.sym = sym_mod; - break; - case AMODU: - p->cond = prog_modu; - p->to.sym = sym_modu; - break; - } - - /* MOV REGTMP, b */ - q = prg(); - q->link = p->link; - p->link = q; - p = q; - - p->as = AMOVW; - p->line = q1->line; - p->from.type = D_REG; - p->from.reg = prog_div != UP && prog_div->from.sym->thumb ? REGTMPT : REGTMP; - p->from.offset = 0; - p->to.type = D_REG; - p->to.reg = q1->to.reg; - - /* ADD $8,SP */ - q = prg(); - q->link = p->link; - p->link = q; - p = q; - - p->as = AADD; - p->from.type = D_CONST; - p->from.reg = NREG; - p->from.offset = 8; - p->reg = NREG; - p->to.type = D_REG; - p->to.reg = REGSP; - - /* SUB $8,SP */ - q1->as = ASUB; - q1->from.type = D_CONST; - q1->from.offset = 8; - q1->from.reg = NREG; - q1->reg = NREG; - q1->to.type = D_REG; - q1->to.reg = REGSP; - - break; case AMOVW: if(thumb){ Adr *a = &p->from; @@ -786,105 +658,6 @@ noops(void) } } -static void -sigdiv(char *n) -{ - Sym *s; - - s = lookup(n, 0); - if(s->type == STEXT){ - if(s->sig == 0) - s->sig = SIGNINTERN; - } - else if(s->type == 0 || s->type == SXREF) - s->type = SUNDEF; -} - -void -divsig(void) -{ - sigdiv("_div"); - sigdiv("_divu"); - sigdiv("_mod"); - sigdiv("_modu"); -} - -static void -sdiv(Sym *s) -{ - if(s->type == 0 || s->type == SXREF){ - /* undefsym(s); */ - s->type = SXREF; - if(s->sig == 0) - s->sig = SIGNINTERN; - s->subtype = SIMPORT; - } - else if(s->type != STEXT) - diag("undefined: %s", s->name); -} - -void -initdiv(void) -{ - Sym *s2, *s3, *s4, *s5; - Prog *p; - - if(prog_div != P) - return; - sym_div = s2 = lookup("_div", 0); - sym_divu = s3 = lookup("_divu", 0); - sym_mod = s4 = lookup("_mod", 0); - sym_modu = s5 = lookup("_modu", 0); - if(dlm) { - sdiv(s2); if(s2->type == SXREF) prog_div = UP; - sdiv(s3); if(s3->type == SXREF) prog_divu = UP; - sdiv(s4); if(s4->type == SXREF) prog_mod = UP; - sdiv(s5); if(s5->type == SXREF) prog_modu = UP; - } - for(p = firstp; p != P; p = p->link) - if(p->as == ATEXT) { - if(p->from.sym == s2) - prog_div = p; - if(p->from.sym == s3) - prog_divu = p; - if(p->from.sym == s4) - prog_mod = p; - if(p->from.sym == s5) - prog_modu = p; - } - if(prog_div == P) { - diag("undefined: %s", s2->name); - prog_div = curtext; - } - if(prog_divu == P) { - diag("undefined: %s", s3->name); - prog_divu = curtext; - } - if(prog_mod == P) { - diag("undefined: %s", s4->name); - prog_mod = curtext; - } - if(prog_modu == P) { - diag("undefined: %s", s5->name); - prog_modu = curtext; - } -} - -static void -setdiv(int as) -{ - Prog *p = nil; - - switch(as){ - case ADIV: p = prog_div; break; - case ADIVU: p = prog_divu; break; - case AMOD: p = prog_mod; break; - case AMODU: p = prog_modu; break; - } - if(p != UP && thumb != p->from.sym->thumb) - p->from.sym->foreign = 1; -} - void nocache(Prog *p) { diff --git a/utils/tl/obj.c b/utils/tl/obj.c index 35c5f558..6cc64dc0 100644 --- a/utils/tl/obj.c +++ b/utils/tl/obj.c @@ -242,15 +242,12 @@ main(int argc, char *argv[]) zerosig("edata"); zerosig("end"); if(dlm){ - initdiv(); import(); HEADTYPE = 2; INITTEXT = INITDAT = 0; INITRND = 8; INITENTRY = EXPTAB; } - else - divsig(); export(); } patch(); @@ -1485,6 +1482,7 @@ static void puntfp(Prog *p) { USED(p); + return; /* floating point - punt for now */ curtext->reg = NREG; /* ARM */ curtext->from.sym->thumb = 0; diff --git a/utils/tl/pass.c b/utils/tl/pass.c index e4322df5..c3725e74 100644 --- a/utils/tl/pass.c +++ b/utils/tl/pass.c @@ -512,10 +512,6 @@ reachable() int i, todo; char *a; - Reachable("_div"); - Reachable("_divu"); - Reachable("_mod"); - Reachable("_modu"); a = INITENTRY; if(*a >= '0' && *a <= '9') return; diff --git a/utils/tl/span.c b/utils/tl/span.c index 85f27621..6d5a0443 100644 --- a/utils/tl/span.c +++ b/utils/tl/span.c @@ -350,6 +350,7 @@ span(void) * add strings to text segment */ c = rnd(c, 8); + INITRODAT = c; for(i=0; i<NHASH; i++) for(s = hash[i]; s != S; s = s->link) { if(s->type != SSTRING) @@ -358,6 +359,7 @@ span(void) while(v & 3) v++; s->value = c; + s->base = -INITDAT; // compensate for assumptions in thumb.c c += v; } } @@ -771,6 +773,7 @@ Optab* oplook(Prog *p) { int a1, a2, a3, r; + int oa1, oa2, oa3; char *c1, *c3; Optab *o, *e; Optab *otab; @@ -808,6 +811,9 @@ oplook(Prog *p) a2 = C_NONE; if(p->reg != NREG) a2 = C_REG; + + oa1 = a1; oa2 = a2; oa3 = a3; + r = p->as; o = orange[r].start; if(o == 0) { @@ -834,7 +840,7 @@ oplook(Prog *p) return o; } diag("illegal combination %A %d %d %d", - p->as, a1, a2, a3); + p->as, oa1, oa2, oa3); prasm(p); if(o == 0) o = otab; diff --git a/utils/tl/thumb.c b/utils/tl/thumb.c index f16175ea..a309f82b 100644 --- a/utils/tl/thumb.c +++ b/utils/tl/thumb.c @@ -2,6 +2,9 @@ static long thumboprr(int); static long thumboprrr(int, int); +static long thumbopfp(int, int); +static long thumbomvl(Prog *p, Adr *a, int dr); +static long thumbofsr(int a, int r, long v, int b, Prog *p); static long thumbopirr(int , int); static long thumbopri(int); static long thumbophh(int); @@ -13,6 +16,11 @@ static void numr(Prog *, int, int, int); static void regis(Prog *, int, int, int); static void dis(int, int); +/* Encode the 32-bit instructions as two 16-bit ones */ +#define SPLIT_INS(filled, empty) \ + empty = filled >> 16; \ + filled = filled & 0xffff; + // build a constant using neg, add and shift - only worth it if < 6 bytes */ static int immbuildcon(int c, Prog *p) @@ -48,7 +56,7 @@ immoreg(int off, Prog *p) if(off < 0) return C_GOREG; - if(as == AMOVW) + if(as == AMOVW || as == AMOVF || as == AMOVD) v = 4; else if(as == AMOVH || as == AMOVHU) v = 2; @@ -80,11 +88,12 @@ immacon(int off, Prog *p, int t1, int t2) static int immauto(int off, Prog *p) { - if(p->as != AMOVW) - diag("bad op in immauto"); + if(p->as != AMOVW && p->as != AMOVF && p->as != AMOVD) + diag("bad op %d in immauto", p->as); mult(p, off, 4); if(off >= 0 && off <= 1020) return C_SAUTO; + return C_LAUTO; } @@ -153,7 +162,6 @@ thumbaclass(Adr *a, Prog *p) diag("D_SHIFT in thumbaclass"); return C_SHIFT; case D_FREG: - diag("D_FREG in thumbaclass"); return C_FREG; case D_FPCR: diag("D_FPCR in thumbaclass"); @@ -173,7 +181,7 @@ thumbaclass(Adr *a, Prog *p) a->sym->name, TNAME); a->sym->type = SDATA; } - instoffset = a->sym->value + a->offset + INITDAT; + instoffset = a->sym->value + a->offset + INITDAT + a->sym->base; return C_LEXT; /* INITDAT unknown at this stage */ // return immacon(instoffset, p, C_SEXT, C_LEXT); case D_AUTO: @@ -205,7 +213,7 @@ thumbaclass(Adr *a, Prog *p) s->name, TNAME); s->type = SDATA; } - instoffset = s->value + a->offset + INITDAT; + instoffset = s->value + a->offset + INITDAT + s->base; if(s->type == STEXT || s->type == SLEAF){ instoffset = s->value + a->offset; #ifdef CALLEEBX @@ -221,7 +229,6 @@ thumbaclass(Adr *a, Prog *p) } return C_GOK; case D_FCONST: - diag("D_FCONST in thumaclass"); return C_FCON; case D_CONST: switch(a->name) { @@ -255,7 +262,7 @@ thumbaclass(Adr *a, Prog *p) #endif return C_LCON; } - instoffset = s->value + a->offset + INITDAT; + instoffset = s->value + a->offset + INITDAT + s->base; return C_LCON; /* INITDAT unknown at this stage */ // return immcon(instoffset, p); case D_AUTO: @@ -339,7 +346,6 @@ Optab thumboptab[] = { AADD, C_SCON, C_REG, C_REG, 3, 2, 0 }, { AADD, C_LCON, C_REG, C_REG, 49, 4, 0 }, { AADD, C_GCON, C_REG, C_REG, 36, 4, 0, LFROM }, - // { AADD, C_LCON, C_NONE, C_REG, 3, 2, 0, LFROM }, { ASRL, C_SCON, C_REG, C_REG, 4, 2, 0 }, { ASRL, C_SCON, C_NONE, C_REG, 4, 2, 0 }, { AADD, C_SCON, C_NONE, C_REG, 5, 2, 0 }, @@ -350,6 +356,9 @@ Optab thumboptab[] = { AMOVW, C_SCON, C_NONE, C_REG, 5, 2, 0 }, { AMOVW, C_BCON, C_NONE, C_REG, 47, 4, 0 }, { AMOVW, C_LCON, C_NONE, C_REG, 38, 2, 0, LFROM }, + { AMVN, C_LCON, C_NONE, C_REG, 61, 4, 0 }, + { AMVN, C_LCON, C_REG, C_REG, 61, 4, 0 }, + { ARSB, C_LCON, C_REG, C_REG, 61, 4, 0 }, // { AADD, C_LCON, C_PC, C_REG, 6, 2, 0, LFROM }, // { AADD, C_LCON, C_SP, C_REG, 6, 2, 0, LFROM }, { AADD, C_SCON, C_NONE, C_SP, 7, 2, 0 }, @@ -450,10 +459,81 @@ Optab thumboptab[] = { AMOVHU, C_REG, C_NONE, C_LEXT, 31, 4, 0, LTO }, { AMOVBU, C_REG, C_NONE, C_LEXT, 31, 4, 0, LTO }, + { AMOVF, C_FREG, C_NONE, C_FEXT, 52, 4, REGSB }, + { AMOVF, C_FREG, C_NONE, C_FAUTO, 52, 4, REGSP }, + { AMOVF, C_FREG, C_NONE, C_FOREG, 52, 4, 0 }, + + { AMOVD, C_FREG, C_NONE, C_SAUTO, 52, 4, REGSP }, + { AMOVD, C_FREG, C_NONE, C_SOREG, 52, 4, 0 }, + + { AMOVF, C_FEXT, C_NONE, C_FREG, 53, 4, REGSB }, + { AMOVF, C_FAUTO,C_NONE, C_FREG, 53, 4, REGSP }, + { AMOVF, C_FOREG,C_NONE, C_FREG, 53, 4, 0 }, + + { AMOVD, C_SAUTO,C_NONE, C_FREG, 53, 4, REGSP }, + { AMOVD, C_SOREG,C_NONE, C_FREG, 53, 4, 0 }, + + { AMOVF, C_FREG, C_NONE, C_LEXT, 54, 6, REGSB, LTO }, + { AMOVF, C_FREG, C_NONE, C_LAUTO, 54, 8, REGSP, LTO }, + { AMOVF, C_FREG, C_NONE, C_LOREG, 54, 8, 0, LTO }, + + { AMOVD, C_FREG, C_NONE, C_LEXT, 54, 6, REGSB, LTO }, + + { AMOVF, C_LEXT, C_NONE, C_FREG, 55, 6, REGSB, LFROM }, + { AMOVF, C_LAUTO,C_NONE, C_FREG, 55, 8, REGSP, LFROM }, + { AMOVF, C_LOREG,C_NONE, C_FREG, 55, 8, 0, LFROM }, + + { AMOVD, C_LEXT, C_NONE, C_FREG, 55, 6, REGSB, LFROM }, + + { AMOVF, C_FREG, C_NONE, C_ADDR, 68, 8, 0, LTO }, + { AMOVF, C_ADDR, C_NONE, C_FREG, 69, 8, 0, LFROM }, + + { AADDF, C_FREG, C_NONE, C_FREG, 56, 4, 0 }, + { AADDF, C_FREG, C_REG, C_FREG, 56, 4, 0 }, + { AADDF, C_FCON, C_NONE, C_FREG, 56, 4, 0 }, + { AADDF, C_FCON, C_REG, C_FREG, 56, 4, 0 }, + { AMOVF, C_FCON, C_NONE, C_FREG, 56, 4, 0 }, + { AMOVF, C_FREG, C_NONE, C_FREG, 56, 4, 0 }, + + { AADDD, C_FREG, C_NONE, C_FREG, 56, 4, 0 }, + { AADDD, C_FREG, C_REG, C_FREG, 56, 4, 0 }, + { ASUBF, C_FREG, C_NONE, C_FREG, 56, 4, 0 }, + { ASUBF, C_FREG, C_REG, C_FREG, 56, 4, 0 }, + { ASUBD, C_FREG, C_NONE, C_FREG, 56, 4, 0 }, + { ASUBD, C_FREG, C_REG, C_FREG, 56, 4, 0 }, + { ADIVD, C_FREG, C_NONE, C_FREG, 56, 4, 0 }, + { ADIVF, C_FREG, C_NONE, C_FREG, 56, 4, 0 }, + { AMULF, C_FREG, C_NONE, C_FREG, 56, 4, 0 }, + { AMULD, C_FREG, C_NONE, C_FREG, 56, 4, 0 }, + + { AMOVD, C_FREG, C_NONE, C_FREG, 56, 4, 0 }, + { AMOVD, C_FCON, C_NONE, C_FREG, 56, 4, 0 }, + + { ACMPF, C_FREG, C_REG, C_NONE, 57, 8, 0 }, + { ACMPF, C_FCON, C_REG, C_NONE, 57, 8, 0 }, + + { ACMPD, C_FREG, C_REG, C_NONE, 57, 8, 0 }, + { ACMPD, C_FCON, C_REG, C_NONE, 57, 8, 0 }, + + { AMOVFW, C_FREG, C_NONE, C_REG, 58, 8, 0 }, + { AMOVWF, C_REG, C_NONE, C_FREG, 58, 8, 0 }, + { AMOVWD, C_REG, C_NONE, C_FREG, 58, 8, 0 }, + { AMOVDW, C_FREG, C_NONE, C_REG, 58, 8, 0 }, + { AMOVFD, C_FREG, C_NONE, C_FREG, 58, 4, 0 }, + { AMOVDF, C_FREG, C_NONE, C_FREG, 58, 4, 0 }, + + { AMOVW, C_REG, C_NONE, C_FCR, 59, 4, 0 }, + { AMOVW, C_FCR, C_NONE, C_REG, 60, 4, 0 }, + + { ADIV, C_REG, C_NONE, C_REG, 62, 4, 0 }, + { ADIVU, C_REG, C_NONE, C_REG, 62, 4, 0 }, + { AMOD, C_REG, C_NONE, C_REG, 63, 10, 0 }, + { AMODU, C_REG, C_NONE, C_REG, 64, 10, 0 }, + { AXXX, C_NONE, C_NONE, C_NONE, 0, 2, 0 }, }; -#define OPCNTSZ 52 +#define OPCNTSZ 65 int opcount[OPCNTSZ]; // is this too pessimistic ? @@ -642,6 +722,17 @@ thumbbuildop() } } +/* Map chipfloat indices to high and low immediate constant values for VMOV */ +static int thumbfloatmap[] = { + 0x00000007, /* 1 = 2**0 * 1 */ + 0x00000000, /* 2 = 2**1 * 1 */ + 0x00080000, /* 3 = 2**1 * 1.5 */ + 0x00000001, /* 4 = 2**2 * 1 */ + 0x00040001, /* 5 = 2**2 * 1.25 */ + 0x00000006, /* 0.5 = 2**-1 * 1 */ + 0x00040002, /* 10 = 2**3 * 1.25 */ +}; + void thumbasmout(Prog *p, Optab *o) { @@ -1125,6 +1216,337 @@ if(debug['G']) print("%ulx: %s: thumb\n", (ulong)(p->pc), p->from.sym->name); o1 = mvlh(REGPC, REGLINK); // mov pc, lr o2 = mvlh(rt, REGPC); // mov r, pc break; + + case 52: /* floating point store */ + v = regoff(&p->to); + r = p->to.reg; + if(r == NREG) + r = o->param; + o1 = thumbofsr(p->as, p->from.reg, v, r, p); + if (p->as == AMOVD) + o1 |= 1 << 24; + SPLIT_INS(o1, o2); + break; + + case 53: /* floating point load */ + v = regoff(&p->from); + r = p->from.reg; + if(r == NREG) + r = o->param; + o1 = thumbofsr(p->as, p->to.reg, v, r, p) | (1<<4); + SPLIT_INS(o1, o2); + break; + + case 54: /* floating point store, long offset UGLY */ + /* Load an address or offset from a PC-relative address */ + o1 = thumbomvl(p, &p->to, REGTMPT); + if(!o1) + break; + r = p->to.reg; + if(r == NREG) + r = o->param; + if (o->param == REGSB) { + /* Store directly to the address */ + o2 = thumbofsr(p->as, p->from.reg, 0, REGTMPT, p); + SPLIT_INS(o2, o3) + } else { + /* Add the offset to the stack pointer */ + /* ADD (ARM ARM Thumb-2 Supplement, 4.6.4), T2 */ + o2 = 0x4400 | ((REGTMPT & 0x8) << 4) | (r << 3) | (REGTMPT & 0x7); + /* Store to the calculated address */ + o3 = thumbofsr(p->as, p->from.reg, 0, REGTMPT, p); + SPLIT_INS(o3, o4) + } + break; + + case 55: /* floating point load, long offset UGLY */ + /* Load an address or offset from a PC-relative address */ + o1 = thumbomvl(p, &p->from, REGTMPT); + if(!o1) + break; + r = p->from.reg; + if(r == NREG) + r = o->param; + if (o->param == REGSB) { + /* Load directly from the address */ + o2 = thumbofsr(p->as, p->to.reg, 0, REGTMPT, p) | (1<<4); + SPLIT_INS(o2, o3) + } else { + /* Add the offset to the stack pointer */ + /* ADD (ARM ARM Thumb-2 Supplement, 4.6.4), T2 */ + o2 = 0x4400 | ((REGTMPT & 0x8) << 4) | (r << 3) | (REGTMPT & 0x7); + /* Load from the calculated address */ + o3 = thumbofsr(p->as, p->to.reg, 0, REGTMPT, p) | (1<<4); + SPLIT_INS(o3, o4) + } + break; + + case 56: /* floating point arith */ + o1 = thumbopfp(p->as, p->scond); + if(p->from.type == D_FCONST) { + rf = chipfloat(p->from.ieee); + if(rf < 0){ + diag("invalid floating-point immediate\n%P", p); + rf = 0; + } + } else + rf = p->from.reg; + + rt = p->to.reg; + r = p->reg; + if(r == NREG) + r = rt; + + switch (p->as) { + case AADDF: + case ADIVF: + case AMULF: + case ASUBF: +// o1 |= ((r >> 1) & 0xf) | ((r & 1) << 23) | /* Vn */ +// (((rf >> 1) & 0xf)<<16) | ((rf & 1) << 21) | /* Vm */ +// (((rt >> 1) & 0xf)<<28) | ((rt & 1) << 6); /* Vd */ +// break; + case AADDD: + case ADIVD: + case AMULD: + case ASUBD: // assume that NFREG < 16 + o1 |= (r & 0xf) | /* Vn */ + ((rf & 0xf)<<16) | /* Vm */ + ((rt & 0xf)<<28); /* Vd */ + break; + case AMOVF: + case AMOVD: /* TODO: actually use double precision */ + if(p->from.type == D_FCONST) { + if (rf == 0) { + /* Float constant was zero */ + /* VSUB rt, rt, rt (ARMv7-M ARM, A7.7.257) */ + o1 ^= 1 << 7; + o1 |= (rt & 0xf); /* Vn */ + o1 |= ((rt & 0xf)<<16); /* Vm */ + } else { + /* VMOV immediate (ARMv7-M ARM, A7.7.236) */ + o1 ^= 1 << 22; + o1 |= thumbfloatmap[rf - 1]; + } + } else { + /* VMOV register (ARMv7-M ARM, A7.7.237) */ + o1 |= ((rf & 0xf)<<16); /* Vm */ + } + o1 |= ((rt & 0xf)<<28); /* Vd */ + if (p->as == AMOVD) + o1 |= 1 << 24; + break; + default: + print("%A %d %d %d\n", p->as, rf, r, rt); + diag("not implemented: %A", p->as); + break; + } + SPLIT_INS(o1, o2); + break; + + case 57: /* floating point compare */ + o1 = thumbopfp(p->as, p->scond); + rf = p->from.reg; + rt = p->reg; + + if(p->from.type == D_FCONST) { + if(p->from.ieee->h != 0 || p->from.ieee->l != 0) + diag("invalid floating-point immediate\n%P", p); + // VCMP (ARMv7-M ARM, A7.7.223, T2) compare to 0.0 + o1 |= 1; + rf = 0; + } + + // VCMP (ARMv7-M ARM, A7.7.223, T1) + o1 |= ((rf & 0x0f)<<16) | ((rt & 0x0f)<<28); /* Vm, Vd */ + + /* VMRS (ARMv7-M ARM, A7.7.243) with Rt=15 (for flags) */ + o3 = 0x0a10eef1 | (15 << 28); + + SPLIT_INS(o1, o2); + SPLIT_INS(o3, o4); + break; + + case 58: /* floating point fix and float (MOVDW/MOVWD) */ + o1 = thumbopfp(p->as, p->scond); + rf = p->from.reg; + rt = p->to.reg; + + if (p->as == AMOVDF) { + // Vd:D M:Vm - only support 16 registers + o1 |= ((rt & 1) << 6) | ((rt & 0xe) << 27) | ((rf & 0x0f) << 16); + SPLIT_INS(o1, o2); + } else if (p->as == AMOVFD) { + // MOVFD: D:Vd Vm:M - only support 16 registers + o1 |= ((rt & 0x0f)<<28) | ((rf & 1) << 21) | ((rf & 0x0e) << 16); + SPLIT_INS(o1, o2); + } else { + if (p->from.type == D_REG) { // int -> float + // VCVT (A7.7.225) + o3 = o1 | (rt << 16); // Vm:M (*2 to align with doubles) + if (p->as == AMOVWD) + o3 |= rt << 28; // D:Vd + else + o3 |= ((rt >> 1) << 28) | ((rt & 1) << 6); // Vd:D + // VMOV F,R (A7.7.240) + o1 = 0x0a10ee00; + o1 |= rt | rf<<28; // rt = Vn:N (*2 to align with doubles) + } else { // float -> int + // VCVT (A7.7.225) rf -> FREGTMP + o1 |= FREGTMP<<28; // Vd:D + if (p->as == AMOVDW) + o1 |= rf << 16; // M:Vm + else + o1 |= ((rf & 1) << 21) | ((rf >> 1) << 16); // Vm:M + // VMOV R,F (A7.7.240) FREFTMP -> rt + o3 = 0x0a10ee10; + o3 |= FREGTMP | rt<<28; + } + SPLIT_INS(o1, o2); + SPLIT_INS(o3, o4); + } + break; + + case 59: /* move to FP[CS]R */ + diag("59", p); + o1 = ((p->scond & C_SCOND) << 28) | (0xe << 24) | (1<<8) | (1<<4); + o1 |= ((p->to.reg+1)<<21) | (p->from.reg << 12); + break; + + case 60: /* move from FP[CS]R */ + diag("60", p); + o1 = ((p->scond & C_SCOND) << 28) | (0xe << 24) | (1<<8) | (1<<4); + o1 |= ((p->from.reg+1)<<21) | (p->to.reg<<12) | (1<<20); + break; + + case 61: /* op $c, r */ + rt = p->to.reg; + if (p->reg == NREG) + r = rt; + else + r = p->reg; + + thumbaclass(&p->from, p); + + switch (p->as) { + case AAND: + o1 = 0x0000f000; + break; + case AORR: + o1 = 0x0000f040; + break; + case ARSB: + o1 = 0x0000f1c0; + break; + default: + print("%A %d %d %d\n", p->as, instoffset, p->reg, p->to.reg); + diag("not implemented: %A", p->as); + break; + } + + if (p->scond & C_SBIT) + o1 |= (1 << 4); + + /* Only certain ranges of constants are supported. */ + if ((instoffset & 0xff) == instoffset) { + o1 |= r | (rt<<24) | (instoffset << 16); + } else if (((instoffset & 0xff00ff) == instoffset) && + ((instoffset & 0xff) == ((instoffset >> 16) & 0xff))) { + o1 |= r | (rt<<24) | ((instoffset & 0xff) << 16) | (1 << 28); + } else if (((instoffset & 0xff00ff00) == instoffset) && + (((instoffset >> 8) & 0xff) == ((instoffset >> 24) & 0xff))) { + o1 |= r | (rt<<24) | ((instoffset & 0xff) << 16) | (2 << 28); + } else if (((instoffset & 0xff) == ((instoffset >> 8) & 0xff)) && + ((instoffset & 0xff) == ((instoffset >> 16) & 0xff)) && + ((instoffset & 0xff) == ((instoffset >> 24) & 0xff))) { + o1 |= r | (rt<<24) | ((instoffset & 0xff) << 16) | (3 << 28); + } else { + print("%A %d %d %d\n", p->as, instoffset, p->reg, p->to.reg); + diag("constant not supported: %ux", instoffset); + } + SPLIT_INS(o1, o2); + break; + + case 62: /* div(u) */ + rf = p->from.reg; + rt = p->to.reg; + if (p->reg == NREG) + r = rt; + else + r = p->reg; + + switch (p->as) { + case ADIV: + /* SDIV (4.6.126, ARM Architecture Reference Manual Thumb-2 Supplement) */ + o1 = 0xf0f0fb90; + break; + case ADIVU: + /* UDIV (4.6.198, ARM Architecture Reference Manual Thumb-2 Supplement) */ + o1 = 0xf0f0fbb0; + break; + default: + print("%A %d %d %d\n", p->as, rf, r, rt); + diag("not implemented: %A", p->as); + break; + } + + o1 |= r | (rf<<16) | (rt<<24); + SPLIT_INS(o1, o2); + break; + + case 63: /* mod */ + rf = p->from.reg; + rt = p->to.reg; + lowreg(p, rf); + lowreg(p, rt); + if (p->reg == NREG) + r = rt; + else + r = p->reg; + + /* rf is Rm in the manual, which is the second operand */ + + /* From ARM Architecture Reference Manual Thumb-2 Supplement, A-16: + x MOD y = x - y * (x DIV y) */ + /* TMP = N SDIV D or TMP = r / rf */ + o1 = 0xf0f0fb90 | (REGTMPT<<24) | r | (rf<<16); + /* MUL (4.6.84, ARM Architecture Reference Manual Thumb-2 Supplement) */ + /* TMP = D * (N DIV D) or TMP = TMP * rf */ + o3 = 0xf000fb00 | (REGTMPT<<24) | (rf<<16) | REGTMPT; + /* SUB (4.6.177, ARM Architecture Reference Manual Thumb-2 Supplement) */ + /* Q = N - D * (N DIV D) */ + o5 = 0x1a00 | (REGTMPT<<6) | (r<<3) | rt; + + SPLIT_INS(o1, o2); + SPLIT_INS(o3, o4); + break; + + case 64: /* modu */ + rf = p->from.reg; + rt = p->to.reg; + lowreg(p, rf); + lowreg(p, rt); + if (p->reg == NREG) + r = rt; + else + r = p->reg; + + /* rf is Rm in the manual, which is the second operand */ + + /* From ARM Architecture Reference Manual Thumb-2 Supplement, A-16: + x MOD y = x - y * (x DIV y) */ + /* TMP = N UDIV D or TMP = r / rf */ + o1 = 0xf0f0fbb0 | (REGTMPT<<24) | r | (rf<<16); + /* MUL (4.6.84, ARM Architecture Reference Manual Thumb-2 Supplement) */ + /* TMP = D * (N DIV D) or TMP = TMP * rf */ + o3 = 0xf000fb00 | (REGTMPT<<24) | (rf<<16) | REGTMPT; + /* SUB (4.6.177, ARM Architecture Reference Manual Thumb-2 Supplement) */ + /* Q = N - D * (N DIV D) */ + o5 = 0x1a00 | (REGTMPT<<6) | (r<<3) | rt; + + SPLIT_INS(o1, o2); + SPLIT_INS(o3, o4); + break; } v = p->pc; @@ -1277,6 +1699,92 @@ thumboprrr(int a, int ld) return 0; } +long +thumbopfp(int a, int sc) +{ + /* See opvfprrr in 5l/asm.c for hints. */ + long o = 0; + + o |= 0xee00; // Prepare the first half-word in the sequence. + + // VCVT opc2 bits are to_int,0,signed + + switch(a) { + case AMOVWF: + /* VCVT (ARMv7-M ARM, A7.7.225), encoding T1, op=1, sz=0, opc2=b_000 */ + return o | (0x0a << 24) | (0xc0 << 16) | 0xb8; + case AMOVFW: + /* VCVT (ARMv7-M ARM, A7.7.225), encoding T1, op=1, sz=0, opc2=b_101 */ + return o | (0x0a << 24) | (0xc0 << 16) | 0xbd; + case AMOVWD: + /* VCVT (ARMv7-M ARM, A7.7.225), encoding T1, op=1, sz=1, opc2=b_000 */ + return o | (0x0b << 24) | (0xc0 << 16) | 0xb8; + case AMOVDW: + /* VCVT (ARMv7-M ARM, A7.7.225), encoding T1, op=1, sz=1, opc2=b_101 */ + return o | (0x0b << 24) | (0xc0 << 16) | 0xbd; + /* VCVT (ARMv7-M ARM, A7.7.227), encoding T1 */ + case AMOVFD: return o | (0x0a<<24) | (0xc0<<16) | 0xb7; + case AMOVDF: return o | (0x0b<<24) | (0xc0<<16) | 0xb7; + /* VMOV (register) (ARMv7-M ARM, A7.7.237) */ + case AMOVF: return o | (0x0a<<24) | (0x40<<16) | 0xb0; + case AMOVD: return o | (0x0b<<24) | (0x40<<16) | 0xb0; + /* VCMP (ARMv7-M ARM, A7.7.223), encoding T1 */ + case ACMPF: return o | (0x0a<<24) | (0x40<<16) | 0xb4; + case ACMPD: return o | (0x0b<<24) | (0x40<<16) | 0xb4; + /* arguably, ACMPF should expand to RNDF, CMPD */ + /* VADD (ARMv7-M ARM, A7.7.222) */ + case AADDD: return o | (0x0b<<24) | 0x30; + case AADDF: return o | (0x0a<<24) | 0x30; + /* VSUB (ARMv7-M ARM, A7.7.257) */ + case ASUBD: return o | (0x0b<<24) | (0x4<<20) | 0x30; + case ASUBF: return o | (0x0a<<24) | (0x4<<20) | 0x30; + /* VMUL (ARMv7-M ARM, A7.7.245) */ + case AMULD: return o | (0x0b<<24) | 0x20; + case AMULF: return o | (0x0a<<24) | 0x20; + /* VDIV (ARMv7-M ARM, A7.7.229) */ + case ADIVD: return o | (0x0b<<24) | 0x80; + case ADIVF: return o | (0x0a<<24) | 0x80; + } + diag("bad fp %d", a); + prasm(curp); + return 0; +} + +static long +thumbofsr(int a, int r, long v, int b, Prog *p) +{ + long o; + + /* VSTR (ARMv7-M ARM, A7.7.256), encoding T2 */ + o = 0x0a00ed00 | (1 << 7); /* Set U (add offset) by default */ + if(v < 0) { + v = -v; + o ^= 1 << 7; /* clear U if offset is negative */ + } + if(v & 3) + diag("odd offset for floating point op: %d\n%P", v, p); + else if(v >= (1<<10)) + diag("literal span too large: %d\n%P", v, p); + o |= ((v>>2) & 0xFF) << 16; /* offset */ + o |= b; /* Rn */ + o |= ((r & 0x0f) << 28); /* Vd */ + + switch(a) { + default: + diag("bad fst %A", a); + case AMOVD: + /* Make the encoding T1 instead of T2 for double precision */ + o |= 1 << 24; + break; + case AMOVF: + break; + } + + /* The caller will OR the result with 1 << 4 to create a load, if required */ + /* VLDR (ARMv7-M ARM, A7.7.233), encoding T2 */ + return o; +} + static long thumbopri(int a) { @@ -1348,6 +1856,29 @@ thumbopmv(int a, int ld) return 0; } +static long +thumbomvl(Prog *p, Adr *a, int dr) +{ + long v, o1; + if(!p->cond) { + thumbaclass(a, p); + v = immrot(~instoffset); + if(v == 0) { + diag("missing literal"); + prasm(p); + return 0; + } + print("omvl: %d\n", dr); + o1 = thumboprrr(AMVN, dr); + o1 |= v; + } else { + v = p->cond->pc - p->pc - 4; + /* A PC-relative load into dr */ + o1 = mv(p, dr, v); + } + return o1; +} + static void lowreg(Prog *p, int r) { |
