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