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