]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/5l/asm.c
Libflac: Tell it that we have stdint.h so it finds SIZE_MAX
[plan9front.git] / sys / src / cmd / 5l / asm.c
1 #include        "l.h"
2
3 long    OFFSET;
4
5 static Prog *PP;
6
7 long
8 entryvalue(void)
9 {
10         char *a;
11         Sym *s;
12
13         a = INITENTRY;
14         if(*a >= '0' && *a <= '9')
15                 return atolwhex(a);
16         s = lookup(a, 0);
17         if(s->type == 0)
18                 return INITTEXT;
19         switch(s->type) {
20         case STEXT:
21         case SLEAF:
22                 break;
23         case SDATA:
24                 if(dlm)
25                         return s->value+INITDAT;
26         default:
27                 diag("entry not text: %s", s->name);
28         }
29         return s->value;
30 }
31
32 void
33 asmb(void)
34 {
35         Prog *p;
36         long t, etext;
37         Optab *o;
38
39         if(debug['v'])
40                 Bprint(&bso, "%5.2f asm\n", cputime());
41         Bflush(&bso);
42         OFFSET = HEADR;
43         seek(cout, OFFSET, 0);
44         pc = INITTEXT;
45         for(p = firstp; p != P; p = p->link) {
46                 if(p->as == ATEXT) {
47                         curtext = p;
48                         autosize = p->to.offset + 4;
49                 }
50                 if(p->pc != pc) {
51                         diag("phase error %lux sb %lux",
52                                 p->pc, pc);
53                         if(!debug['a'])
54                                 prasm(curp);
55                         pc = p->pc;
56                 }
57                 curp = p;
58                 o = oplook(p);  /* could probably avoid this call */
59                 asmout(p, o);
60                 pc += o->size;
61         }
62
63         if(debug['a'])
64                 Bprint(&bso, "\n");
65         Bflush(&bso);
66         cflush();
67
68         /* output strings in text segment */
69         etext = INITTEXT + textsize;
70         for(t = pc; t < etext; t += sizeof(buf)-100) {
71                 if(etext-t > sizeof(buf)-100)
72                         datblk(t, sizeof(buf)-100, 1);
73                 else
74                         datblk(t, etext-t, 1);
75         }
76
77         curtext = P;
78         switch(HEADTYPE) {
79         case 0:
80         case 1:
81         case 2:
82         case 5:
83         case 7:
84                 OFFSET = HEADR+textsize;
85                 seek(cout, OFFSET, 0);
86                 break;
87         case 3:
88         case 6: /* no header, padded segments */
89                 OFFSET = rnd(HEADR+textsize, 4096);
90                 seek(cout, OFFSET, 0);
91                 break;
92         }
93         if(dlm){
94                 char buf[8];
95
96                 write(cout, buf, INITDAT-textsize);
97                 textsize = INITDAT;
98         }
99         for(t = 0; t < datsize; t += sizeof(buf)-100) {
100                 if(datsize-t > sizeof(buf)-100)
101                         datblk(t, sizeof(buf)-100, 0);
102                 else
103                         datblk(t, datsize-t, 0);
104         }
105
106         symsize = 0;
107         lcsize = 0;
108         if(!debug['s']) {
109                 if(debug['v'])
110                         Bprint(&bso, "%5.2f sym\n", cputime());
111                 Bflush(&bso);
112                 switch(HEADTYPE) {
113                 case 0:
114                 case 1:
115                 case 4:
116                 case 5:
117                         debug['s'] = 1;
118                         break;
119                 case 2:
120                         OFFSET = HEADR+textsize+datsize;
121                         seek(cout, OFFSET, 0);
122                         break;
123                 case 3:
124                 case 6: /* no header, padded segments */
125                         OFFSET += rnd(datsize, 4096);
126                         seek(cout, OFFSET, 0);
127                         break;
128                 case 7:
129                         break;
130                 }
131                 if(!debug['s'])
132                         asmsym();
133                 if(debug['v'])
134                         Bprint(&bso, "%5.2f pc\n", cputime());
135                 Bflush(&bso);
136                 if(!debug['s'])
137                         asmlc();
138                 if(dlm)
139                         asmdyn();
140                 cflush();
141         }
142         else if(dlm){
143                 seek(cout, HEADR+textsize+datsize, 0);
144                 asmdyn();
145                 cflush();
146         }
147
148         if(debug['v'])
149                 Bprint(&bso, "%5.2f header\n", cputime());
150         Bflush(&bso);
151         OFFSET = 0;
152         seek(cout, OFFSET, 0);
153         switch(HEADTYPE) {
154         case 0: /* no header */
155         case 6: /* no header, padded segments */
156                 break;
157         case 1: /* aif for risc os */
158                 lputl(0xe1a00000);              /* NOP - decompress code */
159                 lputl(0xe1a00000);              /* NOP - relocation code */
160                 lputl(0xeb000000 + 12);         /* BL - zero init code */
161                 lputl(0xeb000000 +
162                         (entryvalue()
163                          - INITTEXT
164                          + HEADR
165                          - 12
166                          - 8) / 4);             /* BL - entry code */
167
168                 lputl(0xef000011);              /* SWI - exit code */
169                 lputl(textsize+HEADR);          /* text size */
170                 lputl(datsize);                 /* data size */
171                 lputl(0);                       /* sym size */
172
173                 lputl(bsssize);                 /* bss size */
174                 lputl(0);                       /* sym type */
175                 lputl(INITTEXT-HEADR);          /* text addr */
176                 lputl(0);                       /* workspace - ignored */
177
178                 lputl(32);                      /* addr mode / data addr flag */
179                 lputl(0);                       /* data addr */
180                 for(t=0; t<2; t++)
181                         lputl(0);               /* reserved */
182
183                 for(t=0; t<15; t++)
184                         lputl(0xe1a00000);      /* NOP - zero init code */
185                 lputl(0xe1a0f00e);              /* B (R14) - zero init return */
186                 break;
187         case 2: /* plan 9 */
188                 if(dlm)
189                         lput(0x80000000|0x647); /* magic */
190                 else
191                         lput(0x647);                    /* magic */
192                 lput(textsize);                 /* sizes */
193                 lput(datsize);
194                 lput(bsssize);
195                 lput(symsize);                  /* nsyms */
196                 lput(entryvalue());             /* va of entry */
197                 lput(0L);
198                 lput(lcsize);
199                 break;
200         case 3: /* boot for NetBSD */
201                 lput((143<<16)|0413);           /* magic */
202                 lputl(rnd(HEADR+textsize, 4096));
203                 lputl(rnd(datsize, 4096));
204                 lputl(bsssize);
205                 lputl(symsize);                 /* nsyms */
206                 lputl(entryvalue());            /* va of entry */
207                 lputl(0L);
208                 lputl(0L);
209                 break;
210         case 4: /* boot for IXP1200 */
211                 break;
212         case 5: /* boot for ipaq */
213                 lputl(0xe3300000);              /* nop */
214                 lputl(0xe3300000);              /* nop */
215                 lputl(0xe3300000);              /* nop */
216                 lputl(0xe3300000);              /* nop */
217                 break;
218         case 7: /* elf */
219                 strnput("\177ELF", 4);          /* e_ident */
220                 cput(1);                        /* class = 32 bit */
221                 cput(2);                        /* data = MSB */
222                 cput(1);                        /* version = CURRENT */
223                 strnput("", 9);
224                 lput((2L<<16)|40);              /* type = EXEC; machine = ARM */
225                 lput(1L);                       /* version = CURRENT */
226                 lput(entryvalue());             /* entry vaddr */
227                 lput(52L);                      /* offset to first phdr */
228
229                 debug['S'] = 1;                 /* no symbol table */
230                 if(debug['S']){
231                         lput(HEADR+textsize+datsize+symsize);   /* offset to first shdr */
232                         lput(0L);               /* flags = PPC */
233                         lput((52L<<16)|32L);    /* Ehdr & Phdr sizes*/
234                         lput((4L<<16)|40L);     /* # Phdrs & Shdr size */
235                         lput((4L<<16)|2L);      /* # Shdrs & shdr string size */
236                 }
237                 else{
238                         lput(0L);
239                         lput(0L);               /* flags = PPC */
240                         lput((52L<<16)|32L);    /* Ehdr & Phdr sizes*/
241                         lput((4L<<16)|0L);      /* # Phdrs & Shdr size */
242                         lput((4L<<16)|0L);      /* # Shdrs & shdr string size */
243                 }
244
245                 lput(1L);                       /* text - type = PT_LOAD */
246                 lput(HEADR);                    /* file offset */
247                 lput(INITTEXT);                 /* vaddr */
248                 lput(INITTEXT);                 /* paddr */
249                 lput(textsize);                 /* file size */
250                 lput(textsize);                 /* memory size */
251                 lput(0x05L);                    /* protections = RX */
252                 lput(0);                        /* alignment */
253
254                 lput(1L);                       /* data - type = PT_LOAD */
255                 lput(HEADR+textsize);           /* file offset */
256                 lput(INITDAT);                  /* vaddr */
257                 lput(INITDAT);                  /* paddr */
258                 lput(datsize);                  /* file size */
259                 lput(datsize+bsssize);          /* memory size */
260                 lput(0x07L);                    /* protections = RWX */
261                 lput(0);                        /* alignment */
262
263                 lput(0L);                       /* data - type = PT_NULL */
264                 lput(HEADR+textsize+datsize);   /* file offset */
265                 lput(0L);                       /* vaddr */
266                 lput(0L);                       /* paddr */
267                 lput(symsize);                  /* symbol table size */
268                 lput(lcsize);                   /* line number size */
269                 lput(0x04L);                    /* protections = R */
270                 lput(0x04L);                    /* alignment code?? */
271                 break;
272         }
273         cflush();
274 }
275
276 void
277 strnput(char *s, int n)
278 {
279         for(; *s; s++){
280                 cput(*s);
281                 n--;
282         }
283         for(; n > 0; n--)
284                 cput(0);
285 }
286
287 void
288 cput(int c)
289 {
290         cbp[0] = c;
291         cbp++;
292         cbc--;
293         if(cbc <= 0)
294                 cflush();
295 }
296
297 void
298 wput(long l)
299 {
300
301         cbp[0] = l>>8;
302         cbp[1] = l;
303         cbp += 2;
304         cbc -= 2;
305         if(cbc <= 0)
306                 cflush();
307 }
308
309 void
310 lput(long l)
311 {
312
313         cbp[0] = l>>24;
314         cbp[1] = l>>16;
315         cbp[2] = l>>8;
316         cbp[3] = l;
317         cbp += 4;
318         cbc -= 4;
319         if(cbc <= 0)
320                 cflush();
321 }
322
323 void
324 lputl(long l)
325 {
326
327         cbp[3] = l>>24;
328         cbp[2] = l>>16;
329         cbp[1] = l>>8;
330         cbp[0] = l;
331         cbp += 4;
332         cbc -= 4;
333         if(cbc <= 0)
334                 cflush();
335 }
336
337 void
338 cflush(void)
339 {
340         int n;
341
342         n = sizeof(buf.cbuf) - cbc;
343         if(n)
344                 write(cout, buf.cbuf, n);
345         cbp = buf.cbuf;
346         cbc = sizeof(buf.cbuf);
347 }
348
349 void
350 nopstat(char *f, Count *c)
351 {
352         if(c->outof)
353         Bprint(&bso, "%s delay %ld/%ld (%.2f)\n", f,
354                 c->outof - c->count, c->outof,
355                 (double)(c->outof - c->count)/c->outof);
356 }
357
358 void
359 asmsym(void)
360 {
361         Prog *p;
362         Auto *a;
363         Sym *s;
364         int h;
365
366         s = lookup("etext", 0);
367         if(s->type == STEXT)
368                 putsymb(s->name, 'T', s->value, s->version);
369
370         for(h=0; h<NHASH; h++)
371                 for(s=hash[h]; s!=S; s=s->link)
372                         switch(s->type) {
373                         case SCONST:
374                                 putsymb(s->name, 'D', s->value, s->version);
375                                 continue;
376
377                         case SDATA:
378                                 putsymb(s->name, 'D', s->value+INITDAT, s->version);
379                                 continue;
380
381                         case SBSS:
382                                 putsymb(s->name, 'B', s->value+INITDAT, s->version);
383                                 continue;
384
385                         case SSTRING:
386                                 putsymb(s->name, 'T', s->value, s->version);
387                                 continue;
388
389                         case SFILE:
390                                 putsymb(s->name, 'f', s->value, s->version);
391                                 continue;
392                         }
393
394         for(p=textp; p!=P; p=p->cond) {
395                 s = p->from.sym;
396                 if(s->type != STEXT && s->type != SLEAF)
397                         continue;
398
399                 /* filenames first */
400                 for(a=p->to.autom; a; a=a->link)
401                         if(a->type == D_FILE)
402                                 putsymb(a->asym->name, 'z', a->aoffset, 0);
403                         else
404                         if(a->type == D_FILE1)
405                                 putsymb(a->asym->name, 'Z', a->aoffset, 0);
406
407                 if(s->type == STEXT)
408                         putsymb(s->name, 'T', s->value, s->version);
409                 else
410                         putsymb(s->name, 'L', s->value, s->version);
411
412                 /* frame, auto and param after */
413                 putsymb(".frame", 'm', p->to.offset+4, 0);
414                 for(a=p->to.autom; a; a=a->link)
415                         if(a->type == D_AUTO)
416                                 putsymb(a->asym->name, 'a', -a->aoffset, 0);
417                         else
418                         if(a->type == D_PARAM)
419                                 putsymb(a->asym->name, 'p', a->aoffset, 0);
420         }
421         if(debug['v'] || debug['n'])
422                 Bprint(&bso, "symsize = %lud\n", symsize);
423         Bflush(&bso);
424 }
425
426 void
427 putsymb(char *s, int t, long v, int ver)
428 {
429         int i, f;
430
431         if(t == 'f')
432                 s++;
433         lput(v);
434         if(ver)
435                 t += 'a' - 'A';
436         cput(t+0x80);                   /* 0x80 is variable length */
437
438         if(t == 'Z' || t == 'z') {
439                 cput(s[0]);
440                 for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) {
441                         cput(s[i]);
442                         cput(s[i+1]);
443                 }
444                 cput(0);
445                 cput(0);
446                 i++;
447         }
448         else {
449                 for(i=0; s[i]; i++)
450                         cput(s[i]);
451                 cput(0);
452         }
453         symsize += 4 + 1 + i + 1;
454
455         if(debug['n']) {
456                 if(t == 'z' || t == 'Z') {
457                         Bprint(&bso, "%c %.8lux ", t, v);
458                         for(i=1; s[i] != 0 || s[i+1] != 0; i+=2) {
459                                 f = ((s[i]&0xff) << 8) | (s[i+1]&0xff);
460                                 Bprint(&bso, "/%x", f);
461                         }
462                         Bprint(&bso, "\n");
463                         return;
464                 }
465                 if(ver)
466                         Bprint(&bso, "%c %.8lux %s<%d>\n", t, v, s, ver);
467                 else
468                         Bprint(&bso, "%c %.8lux %s\n", t, v, s);
469         }
470 }
471
472 #define MINLC   4
473 void
474 asmlc(void)
475 {
476         long oldpc, oldlc;
477         Prog *p;
478         long v, s;
479
480         oldpc = INITTEXT;
481         oldlc = 0;
482         for(p = firstp; p != P; p = p->link) {
483                 if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) {
484                         if(p->as == ATEXT)
485                                 curtext = p;
486                         if(debug['V'])
487                                 Bprint(&bso, "%6lux %P\n",
488                                         p->pc, p);
489                         continue;
490                 }
491                 if(debug['V'])
492                         Bprint(&bso, "\t\t%6ld", lcsize);
493                 v = (p->pc - oldpc) / MINLC;
494                 while(v) {
495                         s = 127;
496                         if(v < 127)
497                                 s = v;
498                         cput(s+128);    /* 129-255 +pc */
499                         if(debug['V'])
500                                 Bprint(&bso, " pc+%ld*%d(%ld)", s, MINLC, s+128);
501                         v -= s;
502                         lcsize++;
503                 }
504                 s = p->line - oldlc;
505                 oldlc = p->line;
506                 oldpc = p->pc + MINLC;
507                 if(s > 64 || s < -64) {
508                         cput(0);        /* 0 vv +lc */
509                         cput(s>>24);
510                         cput(s>>16);
511                         cput(s>>8);
512                         cput(s);
513                         if(debug['V']) {
514                                 if(s > 0)
515                                         Bprint(&bso, " lc+%ld(%d,%ld)\n",
516                                                 s, 0, s);
517                                 else
518                                         Bprint(&bso, " lc%ld(%d,%ld)\n",
519                                                 s, 0, s);
520                                 Bprint(&bso, "%6lux %P\n",
521                                         p->pc, p);
522                         }
523                         lcsize += 5;
524                         continue;
525                 }
526                 if(s > 0) {
527                         cput(0+s);      /* 1-64 +lc */
528                         if(debug['V']) {
529                                 Bprint(&bso, " lc+%ld(%ld)\n", s, 0+s);
530                                 Bprint(&bso, "%6lux %P\n",
531                                         p->pc, p);
532                         }
533                 } else {
534                         cput(64-s);     /* 65-128 -lc */
535                         if(debug['V']) {
536                                 Bprint(&bso, " lc%ld(%ld)\n", s, 64-s);
537                                 Bprint(&bso, "%6lux %P\n",
538                                         p->pc, p);
539                         }
540                 }
541                 lcsize++;
542         }
543         while(lcsize & 1) {
544                 s = 129;
545                 cput(s);
546                 lcsize++;
547         }
548         if(debug['v'] || debug['V'])
549                 Bprint(&bso, "lcsize = %ld\n", lcsize);
550         Bflush(&bso);
551 }
552
553 void
554 datblk(long s, long n, int str)
555 {
556         Sym *v;
557         Prog *p;
558         char *cast;
559         long a, l, fl, j, d;
560         int i, c;
561
562         memset(buf.dbuf, 0, n+100);
563         for(p = datap; p != P; p = p->link) {
564                 if(str != (p->from.sym->type == SSTRING))
565                         continue;
566                 curp = p;
567                 a = p->from.sym->value + p->from.offset;
568                 l = a - s;
569                 c = p->reg;
570                 i = 0;
571                 if(l < 0) {
572                         if(l+c <= 0)
573                                 continue;
574                         while(l < 0) {
575                                 l++;
576                                 i++;
577                         }
578                 }
579                 if(l >= n)
580                         continue;
581                 if(p->as != AINIT && p->as != ADYNT && !p->from.sym->dupok) {
582                         for(j=l+(c-i)-1; j>=l; j--)
583                                 if(buf.dbuf[j]) {
584                                         print("%P\n", p);
585                                         diag("multiple initialization");
586                                         break;
587                                 }
588                 }
589                 switch(p->to.type) {
590                 default:
591                         diag("unknown mode in initialization%P", p);
592                         break;
593
594                 case D_FCONST:
595                         switch(c) {
596                         default:
597                         case 4:
598                                 fl = ieeedtof(p->to.ieee);
599                                 cast = (char*)&fl;
600                                 for(; i<c; i++) {
601                                         buf.dbuf[l] = cast[fnuxi4[i]];
602                                         l++;
603                                 }
604                                 break;
605                         case 8:
606                                 cast = (char*)p->to.ieee;
607                                 for(; i<c; i++) {
608                                         buf.dbuf[l] = cast[fnuxi8[i]];
609                                         l++;
610                                 }
611                                 break;
612                         }
613                         break;
614
615                 case D_SCONST:
616                         for(; i<c; i++) {
617                                 buf.dbuf[l] = p->to.sval[i];
618                                 l++;
619                         }
620                         break;
621
622                 case D_CONST:
623                         d = p->to.offset;
624                         v = p->to.sym;
625                         if(v) {
626                                 switch(v->type) {
627                                 case SUNDEF:
628                                         ckoff(v, d);
629                                 case STEXT:
630                                 case SLEAF:
631                                 case SSTRING:
632                                         d += p->to.sym->value;
633                                         break;
634                                 case SDATA:
635                                 case SBSS:
636                                         d += p->to.sym->value + INITDAT;
637                                 }
638                                 if(dlm)
639                                         dynreloc(v, a+INITDAT, 1);
640                         }
641                         cast = (char*)&d;
642                         switch(c) {
643                         default:
644                                 diag("bad nuxi %d %d%P", c, i, curp);
645                                 break;
646                         case 1:
647                                 for(; i<c; i++) {
648                                         buf.dbuf[l] = cast[inuxi1[i]];
649                                         l++;
650                                 }
651                                 break;
652                         case 2:
653                                 for(; i<c; i++) {
654                                         buf.dbuf[l] = cast[inuxi2[i]];
655                                         l++;
656                                 }
657                                 break;
658                         case 4:
659                                 for(; i<c; i++) {
660                                         buf.dbuf[l] = cast[inuxi4[i]];
661                                         l++;
662                                 }
663                                 break;
664                         }
665                         break;
666                 }
667         }
668         write(cout, buf.dbuf, n);
669 }
670
671 void
672 asmout(Prog *p, Optab *o)
673 {
674         long o1, o2, o3, o4, o5, o6, v;
675         int r, rf, rt, rt2;
676         Sym *s;
677
678 PP = p;
679         o1 = 0;
680         o2 = 0;
681         o3 = 0;
682         o4 = 0;
683         o5 = 0;
684         o6 = 0;
685         switch(o->type) {
686         default:
687                 diag("unknown asm %d", o->type);
688                 prasm(p);
689                 break;
690
691         case 0:         /* pseudo ops */
692                 break;
693
694         case 1:         /* op R,[R],R */
695                 o1 = oprrr(p->as, p->scond);
696                 rf = p->from.reg;
697                 rt = p->to.reg;
698                 r = p->reg;
699                 if(p->to.type == D_NONE)
700                         rt = 0;
701                 if(p->as == AMOVW || p->as == AMVN)
702                         r = 0;
703                 else if(r == NREG)
704                         r = rt;
705                 o1 |= rf | (r<<16) | (rt<<12);
706                 break;
707
708         case 2:         /* movbu $I,[R],R */
709                 aclass(&p->from);
710                 o1 = oprrr(p->as, p->scond);
711                 o1 |= immrot(instoffset);
712                 rt = p->to.reg;
713                 r = p->reg;
714                 if(p->to.type == D_NONE)
715                         rt = 0;
716                 if(p->as == AMOVW || p->as == AMVN)
717                         r = 0;
718                 else if(r == NREG)
719                         r = rt;
720                 o1 |= (r<<16) | (rt<<12);
721                 break;
722
723         case 3:         /* add R<<[IR],[R],R */
724         mov:
725                 aclass(&p->from);
726                 o1 = oprrr(p->as, p->scond);
727                 o1 |= p->from.offset;
728                 rt = p->to.reg;
729                 r = p->reg;
730                 if(p->to.type == D_NONE)
731                         rt = 0;
732                 if(p->as == AMOVW || p->as == AMVN)
733                         r = 0;
734                 else if(r == NREG)
735                         r = rt;
736                 o1 |= (r<<16) | (rt<<12);
737                 break;
738
739         case 4:         /* add $I,[R],R */
740                 aclass(&p->from);
741                 o1 = oprrr(AADD, p->scond);
742                 o1 |= immrot(instoffset);
743                 r = p->from.reg;
744                 if(r == NREG)
745                         r = o->param;
746                 o1 |= r << 16;
747                 o1 |= p->to.reg << 12;
748                 break;
749
750         case 5:         /* bra s */
751                 v = -8;
752                 if(p->cond == UP) {
753                         s = p->to.sym;
754                         if(s->type != SUNDEF)
755                                 diag("bad branch sym type");
756                         v = (ulong)s->value >> (Roffset-2);
757                         dynreloc(s, p->pc, 0);
758                 }
759                 else if(p->cond != P)
760                         v = (p->cond->pc - pc) - 8;
761                 o1 = opbra(p->as, p->scond);
762                 o1 |= (v >> 2) & 0xffffff;
763                 break;
764
765         case 6:         /* b ,O(R) -> add $O,R,PC */
766                 aclass(&p->to);
767                 o1 = oprrr(AADD, p->scond);
768                 o1 |= immrot(instoffset);
769                 o1 |= p->to.reg << 16;
770                 o1 |= REGPC << 12;
771                 break;
772
773         case 7:         /* bl ,O(R) -> mov PC,link; add $O,R,PC */
774                 aclass(&p->to);
775                 o1 = oprrr(AADD, p->scond);
776                 o1 |= immrot(0);
777                 o1 |= REGPC << 16;
778                 o1 |= REGLINK << 12;
779
780                 o2 = oprrr(AADD, p->scond);
781                 o2 |= immrot(instoffset);
782                 o2 |= p->to.reg << 16;
783                 o2 |= REGPC << 12;
784                 break;
785
786         case 8:         /* sll $c,[R],R -> mov (R<<$c),R */
787                 aclass(&p->from);
788                 o1 = oprrr(p->as, p->scond);
789                 r = p->reg;
790                 if(r == NREG)
791                         r = p->to.reg;
792                 o1 |= r;
793                 o1 |= (instoffset&31) << 7;
794                 o1 |= p->to.reg << 12;
795                 break;
796
797         case 9:         /* sll R,[R],R -> mov (R<<R),R */
798                 o1 = oprrr(p->as, p->scond);
799                 r = p->reg;
800                 if(r == NREG)
801                         r = p->to.reg;
802                 o1 |= r;
803                 o1 |= (p->from.reg << 8) | (1<<4);
804                 o1 |= p->to.reg << 12;
805                 break;
806
807         case 10:        /* swi [$con] */
808                 o1 = oprrr(p->as, p->scond);
809                 if(p->to.type != D_NONE) {
810                         aclass(&p->to);
811                         o1 |= instoffset & 0xffffff;
812                 }
813                 break;
814
815         case 11:        /* word */
816                 switch(aclass(&p->to)) {
817                 case C_LCON:
818                         if(!dlm)
819                                 break;
820                         if(p->to.name != D_EXTERN && p->to.name != D_STATIC)
821                                 break;
822                 case C_ADDR:
823                         if(p->to.sym->type == SUNDEF)
824                                 ckoff(p->to.sym, p->to.offset);
825                         dynreloc(p->to.sym, p->pc, 1);
826                 }
827                 o1 = instoffset;
828                 break;
829
830         case 12:        /* movw $lcon, reg */
831                 o1 = omvl(p, &p->from, p->to.reg);
832                 break;
833
834         case 13:        /* op $lcon, [R], R */
835                 o1 = omvl(p, &p->from, REGTMP);
836                 if(!o1)
837                         break;
838                 o2 = oprrr(p->as, p->scond);
839                 o2 |= REGTMP;
840                 r = p->reg;
841                 if(p->as == AMOVW || p->as == AMVN)
842                         r = 0;
843                 else if(r == NREG)
844                         r = p->to.reg;
845                 o2 |= r << 16;
846                 if(p->to.type != D_NONE)
847                         o2 |= p->to.reg << 12;
848                 break;
849
850         case 14:        /* movb/movbu/movh/movhu R,R */
851                 o1 = oprrr(ASLL, p->scond);
852
853                 if(p->as == AMOVBU || p->as == AMOVHU)
854                         o2 = oprrr(ASRL, p->scond);
855                 else
856                         o2 = oprrr(ASRA, p->scond);
857
858                 r = p->to.reg;
859                 o1 |= (p->from.reg)|(r<<12);
860                 o2 |= (r)|(r<<12);
861                 if(p->as == AMOVB || p->as == AMOVBU) {
862                         o1 |= (24<<7);
863                         o2 |= (24<<7);
864                 } else {
865                         o1 |= (16<<7);
866                         o2 |= (16<<7);
867                 }
868                 break;
869
870         case 15:        /* mul r,[r,]r */
871                 o1 = oprrr(p->as, p->scond);
872                 rf = p->from.reg;
873                 rt = p->to.reg;
874                 r = p->reg;
875                 if(r == NREG)
876                         r = rt;
877                 if(rt == r) {
878                         r = rf;
879                         rf = rt;
880                 }
881                 if(0)
882                 if(rt == r || rf == REGPC || r == REGPC || rt == REGPC) {
883                         diag("bad registers in MUL");
884                         prasm(p);
885                 }
886                 o1 |= (rf<<8) | r | (rt<<16);
887                 break;
888
889
890         case 16:        /* div r,[r,]r */
891                 o1 = 0xf << 28;
892                 o2 = 0;
893                 break;
894
895         case 17:
896                 o1 = oprrr(p->as, p->scond);
897                 rf = p->from.reg;
898                 rt = p->to.reg;
899                 rt2 = p->to.offset;
900                 r = p->reg;
901                 o1 |= (rf<<8) | r | (rt<<16) | (rt2<<12);
902                 break;
903
904         case 20:        /* mov/movb/movbu R,O(R) */
905                 aclass(&p->to);
906                 r = p->to.reg;
907                 if(r == NREG)
908                         r = o->param;
909                 o1 = osr(p->as, p->from.reg, instoffset, r, p->scond);
910                 break;
911
912         case 21:        /* mov/movbu O(R),R -> lr */
913                 aclass(&p->from);
914                 r = p->from.reg;
915                 if(r == NREG)
916                         r = o->param;
917                 o1 = olr(instoffset, r, p->to.reg, p->scond);
918                 if(p->as != AMOVW)
919                         o1 |= 1<<22;
920                 break;
921
922         case 22:        /* movb/movh/movhu O(R),R -> lr,shl,shr */
923                 aclass(&p->from);
924                 r = p->from.reg;
925                 if(r == NREG)
926                         r = o->param;
927                 o1 = olr(instoffset, r, p->to.reg, p->scond);
928
929                 o2 = oprrr(ASLL, p->scond);
930                 o3 = oprrr(ASRA, p->scond);
931                 r = p->to.reg;
932                 if(p->as == AMOVB) {
933                         o2 |= (24<<7)|(r)|(r<<12);
934                         o3 |= (24<<7)|(r)|(r<<12);
935                 } else {
936                         o2 |= (16<<7)|(r)|(r<<12);
937                         if(p->as == AMOVHU)
938                                 o3 = oprrr(ASRL, p->scond);
939                         o3 |= (16<<7)|(r)|(r<<12);
940                 }
941                 break;
942
943         case 23:        /* movh/movhu R,O(R) -> sb,sb */
944                 aclass(&p->to);
945                 r = p->to.reg;
946                 if(r == NREG)
947                         r = o->param;
948                 o1 = osr(AMOVH, p->from.reg, instoffset, r, p->scond);
949
950                 o2 = oprrr(ASRL, p->scond);
951                 o2 |= (8<<7)|(p->from.reg)|(REGTMP<<12);
952
953                 o3 = osr(AMOVH, REGTMP, instoffset+1, r, p->scond);
954                 break;
955
956         case 30:        /* mov/movb/movbu R,L(R) */
957                 o1 = omvl(p, &p->to, REGTMP);
958                 if(!o1)
959                         break;
960                 r = p->to.reg;
961                 if(r == NREG)
962                         r = o->param;
963                 o2 = osrr(p->from.reg, REGTMP,r, p->scond);
964                 if(p->as != AMOVW)
965                         o2 |= 1<<22;
966                 break;
967
968         case 31:        /* mov/movbu L(R),R -> lr[b] */
969         case 32:        /* movh/movb L(R),R -> lr[b] */
970                 o1 = omvl(p, &p->from, REGTMP);
971                 if(!o1)
972                         break;
973                 r = p->from.reg;
974                 if(r == NREG)
975                         r = o->param;
976                 o2 = olrr(REGTMP,r, p->to.reg, p->scond);
977                 if(p->as == AMOVBU || p->as == AMOVB)
978                         o2 |= 1<<22;
979                 if(o->type == 31)
980                         break;
981
982                 o3 = oprrr(ASLL, p->scond);
983
984                 if(p->as == AMOVBU || p->as == AMOVHU)
985                         o4 = oprrr(ASRL, p->scond);
986                 else
987                         o4 = oprrr(ASRA, p->scond);
988
989                 r = p->to.reg;
990                 o3 |= (r)|(r<<12);
991                 o4 |= (r)|(r<<12);
992                 if(p->as == AMOVB || p->as == AMOVBU) {
993                         o3 |= (24<<7);
994                         o4 |= (24<<7);
995                 } else {
996                         o3 |= (16<<7);
997                         o4 |= (16<<7);
998                 }
999                 break;
1000
1001         case 33:        /* movh/movhu R,L(R) -> sb, sb */
1002                 o1 = omvl(p, &p->to, REGTMP);
1003                 if(!o1)
1004                         break;
1005                 r = p->to.reg;
1006                 if(r == NREG)
1007                         r = o->param;
1008                 o2 = osrr(p->from.reg, REGTMP, r, p->scond);
1009                 o2 |= (1<<22) ;
1010
1011                 o3 = oprrr(ASRL, p->scond);
1012                 o3 |= (8<<7)|(p->from.reg)|(p->from.reg<<12);
1013                 o3 |= (1<<6);   /* ROR 8 */
1014
1015                 o4 = oprrr(AADD, p->scond);
1016                 o4 |= (REGTMP << 12) | (REGTMP << 16);
1017                 o4 |= immrot(1);
1018
1019                 o5 = osrr(p->from.reg, REGTMP,r,p->scond);
1020                 o5 |= (1<<22);
1021
1022                 o6 = oprrr(ASRL, p->scond);
1023                 o6 |= (24<<7)|(p->from.reg)|(p->from.reg<<12);
1024                 o6 |= (1<<6);   /* ROL 8 */
1025
1026                 break;
1027                 
1028         case 34:        /* mov $lacon,R */
1029                 o1 = omvl(p, &p->from, REGTMP);
1030                 if(!o1)
1031                         break;
1032
1033                 o2 = oprrr(AADD, p->scond);
1034                 o2 |= REGTMP;
1035                 r = p->from.reg;
1036                 if(r == NREG)
1037                         r = o->param;
1038                 o2 |= r << 16;
1039                 if(p->to.type != D_NONE)
1040                         o2 |= p->to.reg << 12;
1041                 break;
1042
1043         case 35:        /* mov PSR,R */
1044                 o1 = (2<<23) | (0xf<<16) | (0<<0);
1045                 o1 |= (p->scond & C_SCOND) << 28;
1046                 o1 |= (p->from.reg & 1) << 22;
1047                 o1 |= p->to.reg << 12;
1048                 break;
1049
1050         case 36:        /* mov R,PSR */
1051                 o1 = (2<<23) | (0x29f<<12) | (0<<4);
1052                 if(p->scond & C_FBIT)
1053                         o1 ^= 0x010 << 12;
1054                 o1 |= (p->scond & C_SCOND) << 28;
1055                 o1 |= (p->to.reg & 1) << 22;
1056                 o1 |= p->from.reg << 0;
1057                 break;
1058
1059         case 37:        /* mov $con,PSR */
1060                 aclass(&p->from);
1061                 o1 = (2<<23) | (0x29f<<12) | (0<<4);
1062                 if(p->scond & C_FBIT)
1063                         o1 ^= 0x010 << 12;
1064                 o1 |= (p->scond & C_SCOND) << 28;
1065                 o1 |= immrot(instoffset);
1066                 o1 |= (p->to.reg & 1) << 22;
1067                 o1 |= p->from.reg << 0;
1068                 break;
1069
1070         case 38:        /* movm $con,oreg -> stm */
1071                 o1 = (0x4 << 25);
1072                 o1 |= p->from.offset & 0xffff;
1073                 o1 |= p->to.reg << 16;
1074                 aclass(&p->to);
1075                 goto movm;
1076
1077         case 39:        /* movm oreg,$con -> ldm */
1078                 o1 = (0x4 << 25) | (1 << 20);
1079                 o1 |= p->to.offset & 0xffff;
1080                 o1 |= p->from.reg << 16;
1081                 aclass(&p->from);
1082         movm:
1083                 if(instoffset != 0)
1084                         diag("offset must be zero in MOVM");
1085                 o1 |= (p->scond & C_SCOND) << 28;
1086                 if(p->scond & C_PBIT)
1087                         o1 |= 1 << 24;
1088                 if(p->scond & C_UBIT)
1089                         o1 |= 1 << 23;
1090                 if(p->scond & C_SBIT)
1091                         o1 |= 1 << 22;
1092                 if(p->scond & C_WBIT)
1093                         o1 |= 1 << 21;
1094                 break;
1095
1096         case 40:        /* swp oreg,reg,reg */
1097                 if(p->as != ASTREX){
1098                         aclass(&p->from);
1099                         if(instoffset != 0)
1100                                 diag("offset must be zero in SWP");
1101                 }
1102                 o1 = (0x2<<23) | (0x9<<4);
1103                 if(p->as == ASWPBU)
1104                         o1 |= (1 << 22);
1105                 else if(p->as == ALDREX || p->as == ASTREX){
1106                         o1 |= (1 << 23) | 0xf00;
1107                         if(p->as == ALDREX)
1108                                 o1 |= (1 << 20) | 0xf;
1109                 }
1110                 o1 |= p->from.reg << 16;
1111                 o1 |= p->reg << 0;
1112                 o1 |= p->to.reg << 12;
1113                 o1 |= (p->scond & C_SCOND) << 28;
1114                 break;
1115
1116         case 41:        /* rfe -> movm.s.w.u 0(r13),[r15] */
1117                 o1 = 0xe8fd8000;
1118                 break;
1119
1120         case 42:        /* clrex */
1121                 o1 = 0xf57ff01f;
1122                 break;
1123
1124         case 50:        /* floating point store */
1125                 v = regoff(&p->to);
1126                 r = p->to.reg;
1127                 if(r == NREG)
1128                         r = o->param;
1129                 o1 = ofsr(p->as, p->from.reg, v, r, p->scond, p);
1130                 break;
1131
1132         case 51:        /* floating point load */
1133                 v = regoff(&p->from);
1134                 r = p->from.reg;
1135                 if(r == NREG)
1136                         r = o->param;
1137                 o1 = ofsr(p->as, p->to.reg, v, r, p->scond, p) | (1<<20);
1138                 break;
1139
1140         case 52:        /* floating point store, long offset UGLY */
1141                 o1 = omvl(p, &p->to, REGTMP);
1142                 if(!o1)
1143                         break;
1144                 r = p->to.reg;
1145                 if(r == NREG)
1146                         r = o->param;
1147                 o2 = oprrr(AADD, p->scond) | (REGTMP << 12) | (REGTMP << 16) | r;
1148                 o3 = ofsr(p->as, p->from.reg, 0, REGTMP, p->scond, p);
1149                 break;
1150
1151         case 53:        /* floating point load, long offset UGLY */
1152                 o1 = omvl(p, &p->from, REGTMP);
1153                 if(!o1)
1154                         break;
1155                 r = p->from.reg;
1156                 if(r == NREG)
1157                         r = o->param;
1158                 o2 = oprrr(AADD, p->scond) | (REGTMP << 12) | (REGTMP << 16) | r;
1159                 o3 = ofsr(p->as, p->to.reg, 0, REGTMP, p->scond, p) | (1<<20);
1160                 break;
1161
1162         case 54:        /* floating point arith */
1163                 o1 = oprrr(p->as, p->scond);
1164                 if(p->from.type == D_FCONST) {
1165                         rf = chipfloat(p->from.ieee);
1166                         if(rf < 0){
1167                                 diag("invalid floating-point immediate\n%P", p);
1168                                 rf = 0;
1169                         }
1170                         rf |= (1<<3);
1171                 } else
1172                         rf = p->from.reg;
1173                 rt = p->to.reg;
1174                 r = p->reg;
1175                 if(p->to.type == D_NONE)
1176                         rt = 0; /* CMP[FD] */
1177                 else if(o1 & (1<<15))
1178                         r = 0;  /* monadic */
1179                 else if(r == NREG)
1180                         r = rt;
1181                 o1 |= rf | (r<<16) | (rt<<12);
1182                 break;
1183
1184         case 55:        /* floating point fix and float */
1185                 o1 = oprrr(p->as, p->scond);
1186                 rf = p->from.reg;
1187                 rt = p->to.reg;
1188                 if(p->to.type == D_NONE){
1189                         rt = 0;
1190                         diag("to.type==D_NONE (asm/fp)");
1191                 }
1192                 if(p->from.type == D_REG)
1193                         o1 |= (rf<<12) | (rt<<16);
1194                 else
1195                         o1 |= rf | (rt<<12);
1196                 break;
1197
1198         /* old arm 7500 fp using coproc 1 (1<<8) */
1199         case 56:        /* move to FP[CS]R */
1200                 o1 = ((p->scond & C_SCOND) << 28) | (0xe << 24) | (1<<8) | (1<<4);
1201                 o1 |= ((p->to.reg+1)<<21) | (p->from.reg << 12);
1202                 break;
1203
1204         case 57:        /* move from FP[CS]R */
1205                 o1 = ((p->scond & C_SCOND) << 28) | (0xe << 24) | (1<<8) | (1<<4);
1206                 o1 |= ((p->from.reg+1)<<21) | (p->to.reg<<12) | (1<<20);
1207                 break;
1208         case 58:        /* movbu R,R */
1209                 o1 = oprrr(AAND, p->scond);
1210                 o1 |= immrot(0xff);
1211                 rt = p->to.reg;
1212                 r = p->from.reg;
1213                 if(p->to.type == D_NONE)
1214                         rt = 0;
1215                 if(r == NREG)
1216                         r = rt;
1217                 o1 |= (r<<16) | (rt<<12);
1218                 break;
1219
1220         case 59:        /* movw/bu R<<I(R),R -> ldr indexed */
1221                 if(p->from.reg == NREG) {
1222                         if(p->as != AMOVW)
1223                                 diag("byte MOV from shifter operand");
1224                         goto mov;
1225                 }
1226                 if(p->from.offset&(1<<4))
1227                         diag("bad shift in LDR");
1228                 o1 = olrr(p->from.offset, p->from.reg, p->to.reg, p->scond);
1229                 if(p->as == AMOVBU)
1230                         o1 |= 1<<22;
1231                 break;
1232
1233         case 60:        /* movb R(R),R -> ldrsb indexed */
1234                 if(p->from.reg == NREG) {
1235                         diag("byte MOV from shifter operand");
1236                         goto mov;
1237                 }
1238                 if(p->from.offset&(~0xf))
1239                         diag("bad shift in LDRSB");
1240                 o1 = olhrr(p->from.offset, p->from.reg, p->to.reg, p->scond);
1241                 o1 ^= (1<<5)|(1<<6);
1242                 break;
1243
1244         case 61:        /* movw/b/bu R,R<<[IR](R) -> str indexed */
1245                 if(p->to.reg == NREG)
1246                         diag("MOV to shifter operand");
1247                 o1 = osrr(p->from.reg, p->to.offset, p->to.reg, p->scond);
1248                 if(p->as == AMOVB || p->as == AMOVBU)
1249                         o1 |= 1<<22;
1250                 break;
1251
1252         case 62:        /* case R -> movw       R<<2(PC),PC */
1253                 o1 = olrr(p->from.reg, REGPC, REGPC, p->scond);
1254                 o1 |= 2<<7;
1255                 break;
1256
1257         case 63:        /* bcase */
1258                 if(p->cond != P) {
1259                         o1 = p->cond->pc;
1260                         if(dlm)
1261                                 dynreloc(S, p->pc, 1);
1262                 }
1263                 break;
1264
1265         /* reloc ops */
1266         case 64:        /* mov/movb/movbu R,addr */
1267                 o1 = omvl(p, &p->to, REGTMP);
1268                 if(!o1)
1269                         break;
1270                 o2 = osr(p->as, p->from.reg, 0, REGTMP, p->scond);
1271                 break;
1272
1273         case 65:        /* mov/movbu addr,R */
1274         case 66:        /* movh/movhu/movb addr,R */
1275                 o1 = omvl(p, &p->from, REGTMP);
1276                 if(!o1)
1277                         break;
1278                 o2 = olr(0, REGTMP, p->to.reg, p->scond);
1279                 if(p->as == AMOVBU || p->as == AMOVB)
1280                         o2 |= 1<<22;
1281                 if(o->type == 65)
1282                         break;
1283
1284                 o3 = oprrr(ASLL, p->scond);
1285
1286                 if(p->as == AMOVBU || p->as == AMOVHU)
1287                         o4 = oprrr(ASRL, p->scond);
1288                 else
1289                         o4 = oprrr(ASRA, p->scond);
1290
1291                 r = p->to.reg;
1292                 o3 |= (r)|(r<<12);
1293                 o4 |= (r)|(r<<12);
1294                 if(p->as == AMOVB || p->as == AMOVBU) {
1295                         o3 |= (24<<7);
1296                         o4 |= (24<<7);
1297                 } else {
1298                         o3 |= (16<<7);
1299                         o4 |= (16<<7);
1300                 }
1301                 break;
1302
1303         case 67:        /* movh/movhu R,addr -> sb, sb */
1304                 o1 = omvl(p, &p->to, REGTMP);
1305                 if(!o1)
1306                         break;
1307                 o2 = osr(p->as, p->from.reg, 0, REGTMP, p->scond);
1308
1309                 o3 = oprrr(ASRL, p->scond);
1310                 o3 |= (8<<7)|(p->from.reg)|(p->from.reg<<12);
1311                 o3 |= (1<<6);   /* ROR 8 */
1312
1313                 o4 = oprrr(AADD, p->scond);
1314                 o4 |= (REGTMP << 12) | (REGTMP << 16);
1315                 o4 |= immrot(1);
1316
1317                 o5 = osr(p->as, p->from.reg, 0, REGTMP, p->scond);
1318
1319                 o6 = oprrr(ASRL, p->scond);
1320                 o6 |= (24<<7)|(p->from.reg)|(p->from.reg<<12);
1321                 o6 |= (1<<6);   /* ROL 8 */
1322                 break;
1323
1324         case 68:        /* floating point store -> ADDR */
1325                 o1 = omvl(p, &p->to, REGTMP);
1326                 if(!o1)
1327                         break;
1328                 o2 = ofsr(p->as, p->from.reg, 0, REGTMP, p->scond, p);
1329                 break;
1330
1331         case 69:        /* floating point load <- ADDR */
1332                 o1 = omvl(p, &p->from, REGTMP);
1333                 if(!o1)
1334                         break;
1335                 o2 = ofsr(p->as, p->to.reg, 0, REGTMP, p->scond, p) | (1<<20);
1336                 break;
1337
1338         /* ArmV4 ops: */
1339         case 70:        /* movh/movhu R,O(R) -> strh */
1340                 aclass(&p->to);
1341                 r = p->to.reg;
1342                 if(r == NREG)
1343                         r = o->param;
1344                 o1 = oshr(p->from.reg, instoffset, r, p->scond);
1345                 break;  
1346         case 71:        /* movb/movh/movhu O(R),R -> ldrsb/ldrsh/ldrh */
1347                 aclass(&p->from);
1348                 r = p->from.reg;
1349                 if(r == NREG)
1350                         r = o->param;
1351                 o1 = olhr(instoffset, r, p->to.reg, p->scond);
1352                 if(p->as == AMOVB)
1353                         o1 ^= (1<<5)|(1<<6);
1354                 else if(p->as == AMOVH)
1355                         o1 ^= (1<<6);
1356                 break;
1357         case 72:        /* movh/movhu R,L(R) -> strh */
1358                 o1 = omvl(p, &p->to, REGTMP);
1359                 if(!o1)
1360                         break;
1361                 r = p->to.reg;
1362                 if(r == NREG)
1363                         r = o->param;
1364                 o2 = oshrr(p->from.reg, REGTMP,r, p->scond);
1365                 break;  
1366         case 73:        /* movb/movh/movhu L(R),R -> ldrsb/ldrsh/ldrh */
1367                 o1 = omvl(p, &p->from, REGTMP);
1368                 if(!o1)
1369                         break;
1370                 r = p->from.reg;
1371                 if(r == NREG)
1372                         r = o->param;
1373                 o2 = olhrr(REGTMP, r, p->to.reg, p->scond);
1374                 if(p->as == AMOVB)
1375                         o2 ^= (1<<5)|(1<<6);
1376                 else if(p->as == AMOVH)
1377                         o2 ^= (1<<6);
1378                 break;
1379
1380         /* VFP ops: */
1381         case 74:        /* vfp floating point arith */
1382                 o1 = opvfprrr(p->as, p->scond);
1383                 rf = p->from.reg;
1384                 if(p->from.type == D_FCONST) {
1385                         diag("invalid floating-point immediate\n%P", p);
1386                         rf = 0;
1387                 }
1388                 rt = p->to.reg;
1389                 r = p->reg;
1390                 if(r == NREG)
1391                         r = rt;
1392                 o1 |= rt<<12;
1393                 if(((o1>>20)&0xf) == 0xb)
1394                         o1 |= rf<<0;
1395                 else
1396                         o1 |= r<<16 | rf<<0;
1397                 break;
1398         case 75:        /* vfp floating point compare */
1399                 o1 = opvfprrr(p->as, p->scond);
1400                 rf = p->from.reg;
1401                 if(p->from.type == D_FCONST) {
1402                         if(p->from.ieee->h != 0 || p->from.ieee->l != 0)
1403                                 diag("invalid floating-point immediate\n%P", p);
1404                         o1 |= 1<<16;
1405                         rf = 0;
1406                 }
1407                 rt = p->reg;
1408                 o1 |= rt<<12 | rf<<0;
1409                 o2 = 0x0ef1fa10;        /* MRS APSR_nzcv, FPSCR */
1410                 o2 |= (p->scond & C_SCOND) << 28;
1411                 break;
1412         case 76:        /* vfp floating point fix and float */
1413                 o1 = opvfprrr(p->as, p->scond);
1414                 rf = p->from.reg;
1415                 rt = p->to.reg;
1416                 if(p->from.type == D_REG) {
1417                         o2 = o1 | rt<<12 | rt<<0;
1418                         o1 = 0x0e000a10;        /* VMOV F,R */
1419                         o1 |= (p->scond & C_SCOND) << 28 | rt<<16 | rf<<12;
1420                 } else {
1421                         o1 |= FREGTMP<<12 | rf<<0;
1422                         o2 = 0x0e100a10;        /* VMOV R,F */
1423                         o2 |= (p->scond & C_SCOND) << 28 | FREGTMP<<16 | rt<<12;
1424                 }
1425                 break;
1426         }
1427
1428         if(debug['a'] > 1)
1429                 Bprint(&bso, "%2d ", o->type);
1430
1431         v = p->pc;
1432         switch(o->size) {
1433         default:
1434                 if(debug['a'])
1435                         Bprint(&bso, " %.8lux:\t\t%P\n", v, p);
1436                 break;
1437         case 4:
1438                 if(debug['a'])
1439                         Bprint(&bso, " %.8lux: %.8lux\t%P\n", v, o1, p);
1440                 lputl(o1);
1441                 break;
1442         case 8:
1443                 if(debug['a'])
1444                         Bprint(&bso, " %.8lux: %.8lux %.8lux%P\n", v, o1, o2, p);
1445                 lputl(o1);
1446                 lputl(o2);
1447                 break;
1448         case 12:
1449                 if(debug['a'])
1450                         Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux%P\n", v, o1, o2, o3, p);
1451                 lputl(o1);
1452                 lputl(o2);
1453                 lputl(o3);
1454                 break;
1455         case 16:
1456                 if(debug['a'])
1457                         Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux%P\n",
1458                                 v, o1, o2, o3, o4, p);
1459                 lputl(o1);
1460                 lputl(o2);
1461                 lputl(o3);
1462                 lputl(o4);
1463                 break;
1464         case 20:
1465                 if(debug['a'])
1466                         Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux%P\n",
1467                                 v, o1, o2, o3, o4, o5, p);
1468                 lputl(o1);
1469                 lputl(o2);
1470                 lputl(o3);
1471                 lputl(o4);
1472                 lputl(o5);
1473                 break;
1474         case 24:
1475                 if(debug['a'])
1476                         Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux%P\n",
1477                                 v, o1, o2, o3, o4, o5, o6, p);
1478                 lputl(o1);
1479                 lputl(o2);
1480                 lputl(o3);
1481                 lputl(o4);
1482                 lputl(o5);
1483                 lputl(o6);
1484                 break;
1485         }
1486 }
1487
1488 long
1489 oprrr(int a, int sc)
1490 {
1491         long o;
1492
1493         o = (sc & C_SCOND) << 28;
1494         if(sc & C_SBIT)
1495                 o |= 1 << 20;
1496         if(sc & (C_PBIT|C_WBIT))
1497                 diag(".P/.W on dp instruction");
1498         switch(a) {
1499         case AMULU:
1500         case AMUL:      return o | (0x0<<21) | (0x9<<4);
1501         case AMULA:     return o | (0x1<<21) | (0x9<<4);
1502         case AMULLU:    return o | (0x4<<21) | (0x9<<4);
1503         case AMULL:     return o | (0x6<<21) | (0x9<<4);
1504         case AMULALU:   return o | (0x5<<21) | (0x9<<4);
1505         case AMULAL:    return o | (0x7<<21) | (0x9<<4);
1506         case AAND:      return o | (0x0<<21);
1507         case AEOR:      return o | (0x1<<21);
1508         case ASUB:      return o | (0x2<<21);
1509         case ARSB:      return o | (0x3<<21);
1510         case AADD:      return o | (0x4<<21);
1511         case AADC:      return o | (0x5<<21);
1512         case ASBC:      return o | (0x6<<21);
1513         case ARSC:      return o | (0x7<<21);
1514         case ATST:      return o | (0x8<<21) | (1<<20);
1515         case ATEQ:      return o | (0x9<<21) | (1<<20);
1516         case ACMP:      return o | (0xa<<21) | (1<<20);
1517         case ACMN:      return o | (0xb<<21) | (1<<20);
1518         case AORR:      return o | (0xc<<21);
1519         case AMOVW:     return o | (0xd<<21);
1520         case ABIC:      return o | (0xe<<21);
1521         case AMVN:      return o | (0xf<<21);
1522         case ASLL:      return o | (0xd<<21) | (0<<5);
1523         case ASRL:      return o | (0xd<<21) | (1<<5);
1524         case ASRA:      return o | (0xd<<21) | (2<<5);
1525         case AROR:      return o | (0xd<<21) | (3<<5);
1526         case ASWI:      return o | (0xf<<24);
1527
1528         /* old arm 7500 fp using coproc 1 (1<<8) */
1529         case AADDD:     return o | (0xe<<24) | (0x0<<20) | (1<<8) | (1<<7);
1530         case AADDF:     return o | (0xe<<24) | (0x0<<20) | (1<<8);
1531         case AMULD:     return o | (0xe<<24) | (0x1<<20) | (1<<8) | (1<<7);
1532         case AMULF:     return o | (0xe<<24) | (0x1<<20) | (1<<8);
1533         case ASUBD:     return o | (0xe<<24) | (0x2<<20) | (1<<8) | (1<<7);
1534         case ASUBF:     return o | (0xe<<24) | (0x2<<20) | (1<<8);
1535         case ADIVD:     return o | (0xe<<24) | (0x4<<20) | (1<<8) | (1<<7);
1536         case ADIVF:     return o | (0xe<<24) | (0x4<<20) | (1<<8);
1537         case ACMPD:
1538         case ACMPF:     return o | (0xe<<24) | (0x9<<20) | (0xF<<12) | (1<<8) | (1<<4); /* arguably, ACMPF should expand to RNDF, CMPD */
1539
1540         case AMOVF:
1541         case AMOVDF:    return o | (0xe<<24) | (0x0<<20) | (1<<15) | (1<<8);
1542         case AMOVD:
1543         case AMOVFD:    return o | (0xe<<24) | (0x0<<20) | (1<<15) | (1<<8) | (1<<7);
1544
1545         case AMOVWF:    return o | (0xe<<24) | (0<<20) | (1<<8) | (1<<4);
1546         case AMOVWD:    return o | (0xe<<24) | (0<<20) | (1<<8) | (1<<4) | (1<<7);
1547         case AMOVFW:    return o | (0xe<<24) | (1<<20) | (1<<8) | (1<<4);
1548         case AMOVDW:    return o | (0xe<<24) | (1<<20) | (1<<8) | (1<<4) | (1<<7);
1549         }
1550         diag("bad rrr %d", a);
1551         prasm(curp);
1552         return 0;
1553 }
1554
1555 long
1556 opvfprrr(int a, int sc)
1557 {
1558         long o;
1559
1560         o = (sc & C_SCOND) << 28;
1561         if(sc & (C_SBIT|C_PBIT|C_WBIT))
1562                 diag(".S/.P/.W on vfp instruction");
1563         o |= 0xe<<24;
1564         switch(a) {
1565         case AMOVWD:    return o | 0xb<<8 | 0xb<<20 | 1<<6 | 0x8<<16 | 1<<7;
1566         case AMOVWF:    return o | 0xa<<8 | 0xb<<20 | 1<<6 | 0x8<<16 | 1<<7;
1567         case AMOVDW:    return o | 0xb<<8 | 0xb<<20 | 1<<6 | 0xD<<16 | 1<<7;
1568         case AMOVFW:    return o | 0xa<<8 | 0xb<<20 | 1<<6 | 0xD<<16 | 1<<7;
1569         case AMOVFD:    return o | 0xa<<8 | 0xb<<20 | 1<<6 | 0x7<<16 | 1<<7;
1570         case AMOVDF:    return o | 0xb<<8 | 0xb<<20 | 1<<6 | 0x7<<16 | 1<<7;
1571         case AMOVF:     return o | 0xa<<8 | 0xb<<20 | 1<<6 | 0x0<<16 | 0<<7;
1572         case AMOVD:     return o | 0xb<<8 | 0xb<<20 | 1<<6 | 0x0<<16 | 0<<7;
1573         case ACMPF:     return o | 0xa<<8 | 0xb<<20 | 1<<6 | 0x4<<16 | 0<<7;
1574         case ACMPD:     return o | 0xb<<8 | 0xb<<20 | 1<<6 | 0x4<<16 | 0<<7;
1575         case AADDF:     return o | 0xa<<8 | 0x3<<20;
1576         case AADDD:     return o | 0xb<<8 | 0x3<<20;
1577         case ASUBF:     return o | 0xa<<8 | 0x3<<20 | 1<<6;
1578         case ASUBD:     return o | 0xb<<8 | 0x3<<20 | 1<<6;
1579         case AMULF:     return o | 0xa<<8 | 0x2<<20;
1580         case AMULD:     return o | 0xb<<8 | 0x2<<20;
1581         case ADIVF:     return o | 0xa<<8 | 0x8<<20;
1582         case ADIVD:     return o | 0xb<<8 | 0x8<<20;
1583         }
1584         diag("bad vfp rrr %d", a);
1585         prasm(curp);
1586         return 0;
1587 }
1588
1589 long
1590 opbra(int a, int sc)
1591 {
1592
1593         if(sc & (C_SBIT|C_PBIT|C_WBIT))
1594                 diag(".S/.P/.W on bra instruction");
1595         sc &= C_SCOND;
1596         if(a == ABL)
1597                 return (sc<<28)|(0x5<<25)|(0x1<<24);
1598         if(sc != 0xe)
1599                 diag(".COND on bcond instruction");
1600         switch(a) {
1601         case ABEQ:      return (0x0<<28)|(0x5<<25);
1602         case ABNE:      return (0x1<<28)|(0x5<<25);
1603         case ABCS:      return (0x2<<28)|(0x5<<25);
1604         case ABHS:      return (0x2<<28)|(0x5<<25);
1605         case ABCC:      return (0x3<<28)|(0x5<<25);
1606         case ABLO:      return (0x3<<28)|(0x5<<25);
1607         case ABMI:      return (0x4<<28)|(0x5<<25);
1608         case ABPL:      return (0x5<<28)|(0x5<<25);
1609         case ABVS:      return (0x6<<28)|(0x5<<25);
1610         case ABVC:      return (0x7<<28)|(0x5<<25);
1611         case ABHI:      return (0x8<<28)|(0x5<<25);
1612         case ABLS:      return (0x9<<28)|(0x5<<25);
1613         case ABGE:      return (0xa<<28)|(0x5<<25);
1614         case ABLT:      return (0xb<<28)|(0x5<<25);
1615         case ABGT:      return (0xc<<28)|(0x5<<25);
1616         case ABLE:      return (0xd<<28)|(0x5<<25);
1617         case AB:        return (0xe<<28)|(0x5<<25);
1618         }
1619         diag("bad bra %A", a);
1620         prasm(curp);
1621         return 0;
1622 }
1623
1624 long
1625 olr(long v, int b, int r, int sc)
1626 {
1627         long o;
1628
1629         if(sc & C_SBIT)
1630                 diag(".S on LDR/STR instruction");
1631         o = (sc & C_SCOND) << 28;
1632         if(!(sc & C_PBIT))
1633                 o |= 1 << 24;
1634         if(!(sc & C_UBIT))
1635                 o |= 1 << 23;
1636         if(sc & C_WBIT)
1637                 o |= 1 << 21;
1638         o |= (0x1<<26) | (1<<20);
1639         if(v < 0) {
1640                 v = -v;
1641                 o ^= 1 << 23;
1642         }
1643         if(v >= (1<<12))
1644                 diag("literal span too large: %ld (R%d)\n%P", v, b, PP);
1645         o |= v;
1646         o |= b << 16;
1647         o |= r << 12;
1648         return o;
1649 }
1650
1651 long
1652 olhr(long v, int b, int r, int sc)
1653 {
1654         long o;
1655
1656         if(sc & C_SBIT)
1657                 diag(".S on LDRH/STRH instruction");
1658         o = (sc & C_SCOND) << 28;
1659         if(!(sc & C_PBIT))
1660                 o |= 1 << 24;
1661         if(sc & C_WBIT)
1662                 o |= 1 << 21;
1663         o |= (1<<23) | (1<<20)|(0xb<<4);
1664         if(v < 0) {
1665                 v = -v;
1666                 o ^= 1 << 23;
1667         }
1668         if(v >= (1<<8))
1669                 diag("literal span too large: %ld (R%d)\n%P", v, b, PP);
1670         o |= (v&0xf)|((v>>4)<<8)|(1<<22);
1671         o |= b << 16;
1672         o |= r << 12;
1673         return o;
1674 }
1675
1676 long
1677 osr(int a, int r, long v, int b, int sc)
1678 {
1679         long o;
1680
1681         o = olr(v, b, r, sc) ^ (1<<20);
1682         if(a != AMOVW)
1683                 o |= 1<<22;
1684         return o;
1685 }
1686
1687 long
1688 oshr(int r, long v, int b, int sc)
1689 {
1690         long o;
1691
1692         o = olhr(v, b, r, sc) ^ (1<<20);
1693         return o;
1694 }
1695         
1696
1697 long
1698 osrr(int r, int i, int b, int sc)
1699 {
1700
1701         return olr(i, b, r, sc) ^ ((1<<25) | (1<<20));
1702 }
1703
1704 long
1705 oshrr(int r, int i, int b, int sc)
1706 {
1707         return olhr(i, b, r, sc) ^ ((1<<22) | (1<<20));
1708 }
1709
1710 long
1711 olrr(int i, int b, int r, int sc)
1712 {
1713
1714         return olr(i, b, r, sc) ^ (1<<25);
1715 }
1716
1717 long
1718 olhrr(int i, int b, int r, int sc)
1719 {
1720         return olhr(i, b, r, sc) ^ (1<<22);
1721 }
1722
1723 long
1724 ovfpmem(int a, int r, long v, int b, int sc, Prog *p)
1725 {
1726         long o;
1727
1728         if(sc & (C_SBIT|C_PBIT|C_WBIT))
1729                 diag(".S/.P/.W on VLDR/VSTR instruction");
1730         o = (sc & C_SCOND) << 28;
1731         o |= 0xd<<24 | (1<<23);
1732         if(v < 0) {
1733                 v = -v;
1734                 o ^= 1 << 23;
1735         }
1736         if(v & 3)
1737                 diag("odd offset for floating point op: %ld\n%P", v, p);
1738         else if(v >= (1<<10))
1739                 diag("literal span too large: %ld\n%P", v, p);
1740         o |= (v>>2) & 0xFF;
1741         o |= b << 16;
1742         o |= r << 12;
1743         switch(a) {
1744         default:
1745                 diag("bad fst %A", a);
1746         case AMOVD:
1747                 o |= 0xb<<8;
1748                 break;
1749         case AMOVF:
1750                 o |= 0xa<<8;
1751                 break;
1752         }
1753         return o;
1754 }
1755
1756 long
1757 ofsr(int a, int r, long v, int b, int sc, Prog *p)
1758 {
1759         long o;
1760
1761         if(vfp)
1762                 return ovfpmem(a, r, v, b, sc, p);
1763         if(sc & C_SBIT)
1764                 diag(".S on FLDR/FSTR instruction");
1765         o = (sc & C_SCOND) << 28;
1766         if(!(sc & C_PBIT))
1767                 o |= 1 << 24;
1768         if(sc & C_WBIT)
1769                 o |= 1 << 21;
1770         o |= (6<<25) | (1<<24) | (1<<23);
1771         if(v < 0) {
1772                 v = -v;
1773                 o ^= 1 << 23;
1774         }
1775         if(v & 3)
1776                 diag("odd offset for floating point op: %ld\n%P", v, p);
1777         else if(v >= (1<<10))
1778                 diag("literal span too large: %ld\n%P", v, p);
1779         o |= (v>>2) & 0xFF;
1780         o |= b << 16;
1781         o |= r << 12;
1782         o |= 1 << 8;
1783
1784         switch(a) {
1785         default:
1786                 diag("bad fst %A", a);
1787         case AMOVD:
1788                 o |= 1<<15;
1789         case AMOVF:
1790                 break;
1791         }
1792         return o;
1793 }
1794
1795 long
1796 omvl(Prog *p, Adr *a, int dr)
1797 {       
1798         long v, o1;
1799         if(!p->cond) {
1800                 aclass(a);
1801                 v = immrot(~instoffset);
1802                 if(v == 0) {
1803                         diag("missing literal");
1804                         prasm(p);
1805                         return 0;
1806                 }
1807                 o1 = oprrr(AMVN, p->scond&C_SCOND);
1808                 o1 |= v;
1809                 o1 |= dr << 12;
1810         } else {
1811                 v = p->cond->pc - p->pc - 8;
1812                 o1 = olr(v, REGPC, dr, p->scond&C_SCOND);
1813         }
1814         return o1;
1815 }
1816
1817 static Ieee chipfloats[] = {
1818         {0x00000000, 0x00000000}, /* 0 */
1819         {0x00000000, 0x3ff00000}, /* 1 */
1820         {0x00000000, 0x40000000}, /* 2 */
1821         {0x00000000, 0x40080000}, /* 3 */
1822         {0x00000000, 0x40100000}, /* 4 */
1823         {0x00000000, 0x40140000}, /* 5 */
1824         {0x00000000, 0x3fe00000}, /* .5 */
1825         {0x00000000, 0x40240000}, /* 10 */
1826 };
1827
1828 int
1829 chipfloat(Ieee *e)
1830 {
1831         Ieee *p;
1832         int n;
1833
1834         if(vfp)
1835                 return -1;
1836         for(n = sizeof(chipfloats)/sizeof(chipfloats[0]); --n >= 0;){
1837                 p = &chipfloats[n];
1838                 if(p->l == e->l && p->h == e->h)
1839                         return n;
1840         }
1841         return -1;
1842 }