summaryrefslogtreecommitdiff
path: root/utils/5l/asm.c
diff options
context:
space:
mode:
Diffstat (limited to 'utils/5l/asm.c')
-rw-r--r--utils/5l/asm.c319
1 files changed, 162 insertions, 157 deletions
diff --git a/utils/5l/asm.c b/utils/5l/asm.c
index 66a7f0c6..53d51c45 100644
--- a/utils/5l/asm.c
+++ b/utils/5l/asm.c
@@ -43,7 +43,6 @@ asmb(void)
seek(cout, OFFSET, 0);
pc = INITTEXT;
for(p = firstp; p != P; p = p->link) {
- setarch(p);
if(p->as == ATEXT) {
curtext = p;
autosize = p->to.offset + 4;
@@ -57,16 +56,9 @@ asmb(void)
}
curp = p;
o = oplook(p); /* could probably avoid this call */
- if(thumb)
- thumbasmout(p, o);
- else
- asmout(p, o);
+ asmout(p, o);
pc += o->size;
}
- while(pc-INITTEXT < textsize) {
- cput(0);
- pc++;
- }
if(debug['a'])
Bprint(&bso, "\n");
@@ -88,10 +80,12 @@ asmb(void)
case 1:
case 2:
case 5:
+ case 7:
OFFSET = HEADR+textsize;
seek(cout, OFFSET, 0);
break;
case 3:
+ case 6: /* no header, padded segments */
OFFSET = rnd(HEADR+textsize, 4096);
seek(cout, OFFSET, 0);
break;
@@ -108,7 +102,6 @@ asmb(void)
else
datblk(t, datsize-t, 0);
}
- cflush();
symsize = 0;
lcsize = 0;
@@ -128,9 +121,12 @@ asmb(void)
seek(cout, OFFSET, 0);
break;
case 3:
+ case 6: /* no header, padded segments */
OFFSET += rnd(datsize, 4096);
seek(cout, OFFSET, 0);
break;
+ case 7:
+ break;
}
if(!debug['s'])
asmsym();
@@ -139,8 +135,6 @@ asmb(void)
Bflush(&bso);
if(!debug['s'])
asmlc();
- if(!debug['s'])
- asmthumbmap();
if(dlm)
asmdyn();
cflush();
@@ -151,7 +145,6 @@ asmb(void)
cflush();
}
- curtext = P;
if(debug['v'])
Bprint(&bso, "%5.2f header\n", cputime());
Bflush(&bso);
@@ -159,6 +152,7 @@ asmb(void)
seek(cout, OFFSET, 0);
switch(HEADTYPE) {
case 0: /* no header */
+ case 6: /* no header, padded segments */
break;
case 1: /* aif for risc os */
lputl(0xe1a00000); /* NOP - decompress code */
@@ -221,16 +215,12 @@ asmb(void)
lputl(0xe3300000); /* nop */
lputl(0xe3300000); /* nop */
break;
+ case 7: /* elf */
+ debug['S'] = 1; /* symbol table */
+ elf32(ARM, ELFDATA2LSB, 0, nil);
+ break;
}
cflush();
- if(debug['c']){
- print("textsize=%ld\n", textsize);
- print("datsize=%ld\n", datsize);
- print("bsssize=%ld\n", bsssize);
- print("symsize=%ld\n", symsize);
- print("lcsize=%ld\n", lcsize);
- print("total=%ld\n", textsize+datsize+bsssize+symsize+lcsize);
- }
}
void
@@ -254,16 +244,6 @@ cput(int c)
cflush();
}
-/*
-void
-cput(long c)
-{
- *cbp++ = c;
- if(--cbc <= 0)
- cflush();
-}
-*/
-
void
wput(long l)
{
@@ -277,11 +257,11 @@ wput(long l)
}
void
-hput(long l)
+wputl(long l)
{
- cbp[0] = l>>8;
- cbp[1] = l;
+ cbp[0] = l;
+ cbp[1] = l>>8;
cbp += 2;
cbc -= 2;
if(cbc <= 0)
@@ -317,11 +297,24 @@ lputl(long l)
}
void
+llput(vlong v)
+{
+ lput(v>>32);
+ lput(v);
+}
+
+void
+llputl(vlong v)
+{
+ lputl(v);
+ lputl(v>>32);
+}
+
+void
cflush(void)
{
int n;
- /* no bug if cbc < 0 since obuf(cbuf) followed by ibuf in buf! */
n = sizeof(buf.cbuf) - cbc;
if(n)
write(cout, buf.cbuf, n);
@@ -463,16 +456,15 @@ asmlc(void)
oldpc = INITTEXT;
oldlc = 0;
for(p = firstp; p != P; p = p->link) {
- setarch(p);
if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) {
if(p->as == ATEXT)
curtext = p;
- if(debug['L'])
+ if(debug['V'])
Bprint(&bso, "%6lux %P\n",
p->pc, p);
continue;
}
- if(debug['L'])
+ if(debug['V'])
Bprint(&bso, "\t\t%6ld", lcsize);
v = (p->pc - oldpc) / MINLC;
while(v) {
@@ -480,7 +472,7 @@ asmlc(void)
if(v < 127)
s = v;
cput(s+128); /* 129-255 +pc */
- if(debug['L'])
+ if(debug['V'])
Bprint(&bso, " pc+%ld*%d(%ld)", s, MINLC, s+128);
v -= s;
lcsize++;
@@ -494,7 +486,7 @@ asmlc(void)
cput(s>>16);
cput(s>>8);
cput(s);
- if(debug['L']) {
+ if(debug['V']) {
if(s > 0)
Bprint(&bso, " lc+%ld(%d,%ld)\n",
s, 0, s);
@@ -509,14 +501,14 @@ asmlc(void)
}
if(s > 0) {
cput(0+s); /* 1-64 +lc */
- if(debug['L']) {
+ if(debug['V']) {
Bprint(&bso, " lc+%ld(%ld)\n", s, 0+s);
Bprint(&bso, "%6lux %P\n",
p->pc, p);
}
} else {
cput(64-s); /* 65-128 -lc */
- if(debug['L']) {
+ if(debug['V']) {
Bprint(&bso, " lc%ld(%ld)\n", s, 64-s);
Bprint(&bso, "%6lux %P\n",
p->pc, p);
@@ -529,62 +521,11 @@ asmlc(void)
cput(s);
lcsize++;
}
- if(debug['v'] || debug['L'])
+ if(debug['v'] || debug['V'])
Bprint(&bso, "lcsize = %ld\n", lcsize);
Bflush(&bso);
}
-static void
-outt(long f, long l)
-{
- if(debug['L'])
- Bprint(&bso, "tmap: %lux-%lux\n", f, l);
- lput(f);
- lput(l);
-}
-
-void
-asmthumbmap(void)
-{
- long pc, lastt;
- Prog *p;
-
- if(!seenthumb)
- return;
- pc = 0;
- lastt = -1;
- for(p = firstp; p != P; p = p->link){
- pc = p->pc - INITTEXT;
- if(p->as == ATEXT){
- setarch(p);
- if(thumb){
- if(p->from.sym->foreign){ // 8 bytes of ARM first
- if(lastt >= 0){
- outt(lastt, pc-1);
- lastt = -1;
- }
- pc += 8;
- }
- if(lastt < 0)
- lastt = pc;
- }
- else{
- if(p->from.sym->foreign){ // 4 bytes of THUMB first
- if(lastt < 0)
- lastt = pc;
- pc += 4;
- }
- if(lastt >= 0){
- outt(lastt, pc-1);
- lastt = -1;
- }
- }
- }
- }
- if(lastt >= 0)
- outt(lastt, pc+1);
-}
-
void
datblk(long s, long n, int str)
{
@@ -661,25 +602,14 @@ datblk(long s, long n, int str)
switch(v->type) {
case SUNDEF:
ckoff(v, d);
- d += v->value;
- break;
case STEXT:
case SLEAF:
- d += v->value;
-#ifdef CALLEEBX
- d += fnpinc(v);
-#else
- if(v->thumb)
- d++; // T bit
-#endif
- break;
case SSTRING:
- d += v->value;
+ d += p->to.sym->value;
break;
case SDATA:
case SBSS:
- d += v->value + INITDAT;
- break;
+ d += p->to.sym->value + INITDAT;
}
if(dlm)
dynreloc(v, a+INITDAT, 1);
@@ -728,8 +658,6 @@ PP = p;
o4 = 0;
o5 = 0;
o6 = 0;
- armsize += o->size;
-if(debug['P']) print("%ulx: %P type %d\n", (ulong)(p->pc), p, o->type);
switch(o->type) {
default:
diag("unknown asm %d", o->type);
@@ -737,7 +665,6 @@ if(debug['P']) print("%ulx: %P type %d\n", (ulong)(p->pc), p, o->type);
break;
case 0: /* pseudo ops */
-if(debug['G']) print("%ulx: %s: arm %d %d %d %d\n", (ulong)(p->pc), p->from.sym->name, p->from.sym->thumb, p->from.sym->foreign, p->from.sym->fnptr, p->from.sym->used);
break;
case 1: /* op R,[R],R */
@@ -807,10 +734,6 @@ if(debug['G']) print("%ulx: %s: arm %d %d %d %d\n", (ulong)(p->pc), p->from.sym-
}
else if(p->cond != P)
v = (p->cond->pc - pc) - 8;
-#ifdef CALLEEBX
- if(p->as == ABL)
- v += fninc(p->to.sym);
-#endif
o1 = opbra(p->as, p->scond);
o1 |= (v >> 2) & 0xffffff;
break;
@@ -1237,6 +1160,7 @@ if(debug['G']) print("%ulx: %s: arm %d %d %d %d\n", (ulong)(p->pc), p->from.sym-
o1 |= rf | (rt<<12);
break;
+ /* old arm 7500 fp using coproc 1 (1<<8) */
case 56: /* move to FP[CS]R */
o1 = ((p->scond & C_SCOND) << 28) | (0xe << 24) | (1<<8) | (1<<4);
o1 |= ((p->to.reg+1)<<21) | (p->from.reg << 12);
@@ -1417,49 +1341,58 @@ if(debug['G']) print("%ulx: %s: arm %d %d %d %d\n", (ulong)(p->pc), p->from.sym-
else if(p->as == AMOVH)
o2 ^= (1<<6);
break;
- case 74: /* bx $I */
-#ifdef CALLEEBX
- diag("bx $i case (arm)");
-#endif
- if(!seenthumb)
- diag("ABX $I and seenthumb==0");
- v = p->cond->pc;
- if(p->to.sym->thumb)
- v |= 1; // T bit
- o1 = olr(8, REGPC, REGTMP, p->scond&C_SCOND); // mov 8(PC), Rtmp
- o2 = oprrr(AADD, p->scond) | immrot(8) | (REGPC<<16) | (REGLINK<<12); // add 8,PC, LR
- o3 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | REGTMP; // bx Rtmp
- o4 = opbra(AB, 14); // B over o6
- o5 = v;
- break;
- case 75: /* bx O(R) */
- aclass(&p->to);
- if(instoffset != 0)
- diag("non-zero offset in ABX");
-/*
- o1 = oprrr(AADD, p->scond) | immrot(0) | (REGPC<<16) | (REGLINK<<12); // mov PC, LR
- o2 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | p->to.reg; // BX R
-*/
- // p->to.reg may be REGLINK
- o1 = oprrr(AADD, p->scond);
- o1 |= immrot(instoffset);
- o1 |= p->to.reg << 16;
- o1 |= REGTMP << 12;
- o2 = oprrr(AADD, p->scond) | immrot(0) | (REGPC<<16) | (REGLINK<<12); // mov PC, LR
- o3 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | REGTMP; // BX Rtmp
+
+ /* VFP ops: */
+ case 74: /* vfp floating point arith */
+ o1 = opvfprrr(p->as, p->scond);
+ rf = p->from.reg;
+ if(p->from.type == D_FCONST) {
+ diag("invalid floating-point immediate\n%P", p);
+ rf = 0;
+ }
+ rt = p->to.reg;
+ r = p->reg;
+ if(r == NREG)
+ r = rt;
+ o1 |= rt<<12;
+ if(((o1>>20)&0xf) == 0xb)
+ o1 |= rf<<0;
+ else
+ o1 |= r<<16 | rf<<0;
break;
- case 76: /* bx O(R) when returning from fn*/
- if(!seenthumb)
- diag("ABXRET and seenthumb==0");
- aclass(&p->to);
-// print("ARM BXRET %d(R%d)\n", instoffset, p->to.reg);
- if(instoffset != 0)
- diag("non-zero offset in ABXRET");
- // o1 = olr(instoffset, p->to.reg, REGTMP, p->scond); // mov O(R), Rtmp
- o1 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | p->to.reg; // BX R
+ case 75: /* vfp floating point compare */
+ o1 = opvfprrr(p->as, p->scond);
+ rf = p->from.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);
+ o1 |= 1<<16;
+ rf = 0;
+ }
+ rt = p->reg;
+ o1 |= rt<<12 | rf<<0;
+ o2 = 0x0ef1fa10; /* MRS APSR_nzcv, FPSCR */
+ o2 |= (p->scond & C_SCOND) << 28;
+ break;
+ case 76: /* vfp floating point fix and float */
+ o1 = opvfprrr(p->as, p->scond);
+ rf = p->from.reg;
+ rt = p->to.reg;
+ if(p->from.type == D_REG) {
+ o2 = o1 | rt<<12 | rt<<0;
+ o1 = 0x0e000a10; /* VMOV F,R */
+ o1 |= (p->scond & C_SCOND) << 28 | rt<<16 | rf<<12;
+ } else {
+ o1 |= FREGTMP<<12 | rf<<0;
+ o2 = 0x0e100a10; /* VMOV R,F */
+ o2 |= (p->scond & C_SCOND) << 28 | FREGTMP<<16 | rt<<12;
+ }
break;
}
+ if(debug['a'] > 1)
+ Bprint(&bso, "%2d ", o->type);
+
v = p->pc;
switch(o->size) {
default:
@@ -1556,6 +1489,7 @@ oprrr(int a, int sc)
case ASRA: return o | (0xd<<21) | (2<<5);
case ASWI: return o | (0xf<<24);
+ /* old arm 7500 fp using coproc 1 (1<<8) */
case AADDD: return o | (0xe<<24) | (0x0<<20) | (1<<8) | (1<<7);
case AADDF: return o | (0xe<<24) | (0x0<<20) | (1<<8);
case AMULD: return o | (0xe<<24) | (0x1<<20) | (1<<8) | (1<<7);
@@ -1583,6 +1517,40 @@ oprrr(int a, int sc)
}
long
+opvfprrr(int a, int sc)
+{
+ long o;
+
+ o = (sc & C_SCOND) << 28;
+ if(sc & (C_SBIT|C_PBIT|C_WBIT))
+ diag(".S/.P/.W on vfp instruction");
+ o |= 0xe<<24;
+ switch(a) {
+ case AMOVWD: return o | 0xb<<8 | 0xb<<20 | 1<<6 | 0x8<<16 | 1<<7;
+ case AMOVWF: return o | 0xa<<8 | 0xb<<20 | 1<<6 | 0x8<<16 | 1<<7;
+ case AMOVDW: return o | 0xb<<8 | 0xb<<20 | 1<<6 | 0xD<<16 | 1<<7;
+ case AMOVFW: return o | 0xa<<8 | 0xb<<20 | 1<<6 | 0xD<<16 | 1<<7;
+ case AMOVFD: return o | 0xa<<8 | 0xb<<20 | 1<<6 | 0x7<<16 | 1<<7;
+ case AMOVDF: return o | 0xb<<8 | 0xb<<20 | 1<<6 | 0x7<<16 | 1<<7;
+ case AMOVF: return o | 0xa<<8 | 0xb<<20 | 1<<6 | 0x0<<16 | 0<<7;
+ case AMOVD: return o | 0xb<<8 | 0xb<<20 | 1<<6 | 0x0<<16 | 0<<7;
+ case ACMPF: return o | 0xa<<8 | 0xb<<20 | 1<<6 | 0x4<<16 | 0<<7;
+ case ACMPD: return o | 0xb<<8 | 0xb<<20 | 1<<6 | 0x4<<16 | 0<<7;
+ case AADDF: return o | 0xa<<8 | 0x3<<20;
+ case AADDD: return o | 0xb<<8 | 0x3<<20;
+ case ASUBF: return o | 0xa<<8 | 0x3<<20 | 1<<6;
+ case ASUBD: return o | 0xb<<8 | 0x3<<20 | 1<<6;
+ case AMULF: return o | 0xa<<8 | 0x2<<20;
+ case AMULD: return o | 0xb<<8 | 0x2<<20;
+ case ADIVF: return o | 0xa<<8 | 0x8<<20;
+ case ADIVD: return o | 0xb<<8 | 0x8<<20;
+ }
+ diag("bad vfp rrr %d", a);
+ prasm(curp);
+ return 0;
+}
+
+long
opbra(int a, int sc)
{
@@ -1637,7 +1605,7 @@ olr(long v, int b, int r, int sc)
o ^= 1 << 23;
}
if(v >= (1<<12))
- diag("literal span too large: %d (R%d)\n%P", v, b, PP);
+ diag("literal span too large: %ld (R%d)\n%P", v, b, PP);
o |= v;
o |= b << 16;
o |= r << 12;
@@ -1662,7 +1630,7 @@ olhr(long v, int b, int r, int sc)
o ^= 1 << 23;
}
if(v >= (1<<8))
- diag("literal span too large: %d (R%d)\n%P", v, b, PP);
+ diag("literal span too large: %ld (R%d)\n%P", v, b, PP);
o |= (v&0xf)|((v>>4)<<8)|(1<<22);
o |= b << 16;
o |= r << 12;
@@ -1717,10 +1685,45 @@ olhrr(int i, int b, int r, int sc)
}
long
+ovfpmem(int a, int r, long v, int b, int sc, Prog *p)
+{
+ long o;
+
+ if(sc & (C_SBIT|C_PBIT|C_WBIT))
+ diag(".S/.P/.W on VLDR/VSTR instruction");
+ o = (sc & C_SCOND) << 28;
+ o |= 0xd<<24 | (1<<23);
+ if(v < 0) {
+ v = -v;
+ o ^= 1 << 23;
+ }
+ if(v & 3)
+ diag("odd offset for floating point op: %ld\n%P", v, p);
+ else if(v >= (1<<10))
+ diag("literal span too large: %ld\n%P", v, p);
+ o |= (v>>2) & 0xFF;
+ o |= b << 16;
+ o |= r << 12;
+ switch(a) {
+ default:
+ diag("bad fst %A", a);
+ case AMOVD:
+ o |= 0xb<<8;
+ break;
+ case AMOVF:
+ o |= 0xa<<8;
+ break;
+ }
+ return o;
+}
+
+long
ofsr(int a, int r, long v, int b, int sc, Prog *p)
{
long o;
+ if(vfp)
+ return ovfpmem(a, r, v, b, sc, p);
if(sc & C_SBIT)
diag(".S on FLDR/FSTR instruction");
o = (sc & C_SCOND) << 28;
@@ -1734,9 +1737,9 @@ ofsr(int a, int r, long v, int b, int sc, Prog *p)
o ^= 1 << 23;
}
if(v & 3)
- diag("odd offset for floating point op: %d\n%P", v, p);
+ diag("odd offset for floating point op: %ld\n%P", v, p);
else if(v >= (1<<10))
- diag("literal span too large: %d\n%P", v, p);
+ diag("literal span too large: %ld\n%P", v, p);
o |= (v>>2) & 0xFF;
o |= b << 16;
o |= r << 12;
@@ -1792,6 +1795,8 @@ chipfloat(Ieee *e)
Ieee *p;
int n;
+ if(vfp)
+ return -1;
for(n = sizeof(chipfloats)/sizeof(chipfloats[0]); --n >= 0;){
p = &chipfloats[n];
if(p->l == e->l && p->h == e->h)