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(r == NREG) 751 r = rt; 752 o1 |= rf | (r<<16) | (rt<<12); 753 break; 754 755 case 2: /* movbu $I,[R],R */ 756 aclass(&p->from); 757 o1 = oprrr(p->as, p->scond); 758 o1 |= immrot(instoffset); 759 rt = p->to.reg; 760 r = p->reg; 761 if(p->to.type == D_NONE) 762 rt = 0; 763 if(r == NREG) 764 r = rt; 765 o1 |= (r<<16) | (rt<<12); 766 break; 767 768 case 3: /* add R<<[IR],[R],R */ 769 mov: 770 aclass(&p->from); 771 o1 = oprrr(p->as, p->scond); 772 o1 |= p->from.offset; 773 rt = p->to.reg; 774 r = p->reg; 775 if(p->to.type == D_NONE) 776 rt = 0; 777 if(r == NREG) 778 r = rt; 779 o1 |= (r<<16) | (rt<<12); 780 break; 781 782 case 4: /* add $I,[R],R */ 783 aclass(&p->from); 784 o1 = oprrr(AADD, p->scond); 785 o1 |= immrot(instoffset); 786 r = p->from.reg; 787 if(r == NREG) 788 r = o->param; 789 o1 |= r << 16; 790 o1 |= p->to.reg << 12; 791 break; 792 793 case 5: /* bra s */ 794 v = -8; 795 if(p->cond == UP) { 796 s = p->to.sym; 797 if(s->type != SUNDEF) 798 diag("bad branch sym type"); 799 v = (ulong)s->value >> (Roffset-2); 800 dynreloc(s, p->pc, 0); 801 } 802 else if(p->cond != P) 803 v = (p->cond->pc - pc) - 8; 804 #ifdef CALLEEBX 805 if(p->as == ABL) 806 v += fninc(p->to.sym); 807 #endif 808 o1 = opbra(p->as, p->scond); 809 o1 |= (v >> 2) & 0xffffff; 810 break; 811 812 case 6: /* b ,O(R) -> add $O,R,PC */ 813 aclass(&p->to); 814 o1 = oprrr(AADD, p->scond); 815 o1 |= immrot(instoffset); 816 o1 |= p->to.reg << 16; 817 o1 |= REGPC << 12; 818 break; 819 820 case 7: /* bl ,O(R) -> mov PC,link; add $O,R,PC */ 821 aclass(&p->to); 822 o1 = oprrr(AADD, p->scond); 823 o1 |= immrot(0); 824 o1 |= REGPC << 16; 825 o1 |= REGLINK << 12; 826 827 o2 = oprrr(AADD, p->scond); 828 o2 |= immrot(instoffset); 829 o2 |= p->to.reg << 16; 830 o2 |= REGPC << 12; 831 break; 832 833 case 8: /* sll $c,[R],R -> mov (R<<$c),R */ 834 aclass(&p->from); 835 o1 = oprrr(p->as, p->scond); 836 r = p->reg; 837 if(r == NREG) 838 r = p->to.reg; 839 o1 |= r; 840 o1 |= (instoffset&31) << 7; 841 o1 |= p->to.reg << 12; 842 break; 843 844 case 9: /* sll R,[R],R -> mov (R<<R),R */ 845 o1 = oprrr(p->as, p->scond); 846 r = p->reg; 847 if(r == NREG) 848 r = p->to.reg; 849 o1 |= r; 850 o1 |= (p->from.reg << 8) | (1<<4); 851 o1 |= p->to.reg << 12; 852 break; 853 854 case 10: /* swi [$con] */ 855 o1 = oprrr(p->as, p->scond); 856 if(p->to.type != D_NONE) { 857 aclass(&p->to); 858 o1 |= instoffset & 0xffffff; 859 } 860 break; 861 862 case 11: /* word */ 863 switch(aclass(&p->to)) { 864 case C_LCON: 865 if(!dlm) 866 break; 867 if(p->to.name != D_EXTERN && p->to.name != D_STATIC) 868 break; 869 case C_ADDR: 870 if(p->to.sym->type == SUNDEF) 871 ckoff(p->to.sym, p->to.offset); 872 dynreloc(p->to.sym, p->pc, 1); 873 } 874 o1 = instoffset; 875 break; 876 877 case 12: /* movw $lcon, reg */ 878 o1 = omvl(p, &p->from, p->to.reg); 879 break; 880 881 case 13: /* op $lcon, [R], R */ 882 o1 = omvl(p, &p->from, REGTMP); 883 if(!o1) 884 break; 885 o2 = oprrr(p->as, p->scond); 886 o2 |= REGTMP; 887 r = p->reg; 888 if(r == NREG) 889 r = p->to.reg; 890 o2 |= r << 16; 891 if(p->to.type != D_NONE) 892 o2 |= p->to.reg << 12; 893 break; 894 895 case 14: /* movb/movbu/movh/movhu R,R */ 896 o1 = oprrr(ASLL, p->scond); 897 898 if(p->as == AMOVBU || p->as == AMOVHU) 899 o2 = oprrr(ASRL, p->scond); 900 else 901 o2 = oprrr(ASRA, p->scond); 902 903 r = p->to.reg; 904 o1 |= (p->from.reg)|(r<<12); 905 o2 |= (r)|(r<<12); 906 if(p->as == AMOVB || p->as == AMOVBU) { 907 o1 |= (24<<7); 908 o2 |= (24<<7); 909 } else { 910 o1 |= (16<<7); 911 o2 |= (16<<7); 912 } 913 break; 914 915 case 15: /* mul r,[r,]r */ 916 o1 = oprrr(p->as, p->scond); 917 rf = p->from.reg; 918 rt = p->to.reg; 919 r = p->reg; 920 if(r == NREG) 921 r = rt; 922 if(rt == r) { 923 r = rf; 924 rf = rt; 925 } 926 if(0) 927 if(rt == r || rf == REGPC || r == REGPC || rt == REGPC) { 928 diag("bad registers in MUL"); 929 prasm(p); 930 } 931 o1 |= (rf<<8) | r | (rt<<16); 932 break; 933 934 935 case 16: /* div r,[r,]r */ 936 o1 = 0xf << 28; 937 o2 = 0; 938 break; 939 940 case 17: 941 o1 = oprrr(p->as, p->scond); 942 rf = p->from.reg; 943 rt = p->to.reg; 944 rt2 = p->to.offset; 945 r = p->reg; 946 o1 |= (rf<<8) | r | (rt<<16) | (rt2<<12); 947 break; 948 949 case 20: /* mov/movb/movbu R,O(R) */ 950 aclass(&p->to); 951 r = p->to.reg; 952 if(r == NREG) 953 r = o->param; 954 o1 = osr(p->as, p->from.reg, instoffset, r, p->scond); 955 break; 956 957 case 21: /* mov/movbu O(R),R -> lr */ 958 aclass(&p->from); 959 r = p->from.reg; 960 if(r == NREG) 961 r = o->param; 962 o1 = olr(instoffset, r, p->to.reg, p->scond); 963 if(p->as != AMOVW) 964 o1 |= 1<<22; 965 break; 966 967 case 22: /* movb/movh/movhu O(R),R -> lr,shl,shr */ 968 aclass(&p->from); 969 r = p->from.reg; 970 if(r == NREG) 971 r = o->param; 972 o1 = olr(instoffset, r, p->to.reg, p->scond); 973 974 o2 = oprrr(ASLL, p->scond); 975 o3 = oprrr(ASRA, p->scond); 976 r = p->to.reg; 977 if(p->as == AMOVB) { 978 o2 |= (24<<7)|(r)|(r<<12); 979 o3 |= (24<<7)|(r)|(r<<12); 980 } else { 981 o2 |= (16<<7)|(r)|(r<<12); 982 if(p->as == AMOVHU) 983 o3 = oprrr(ASRL, p->scond); 984 o3 |= (16<<7)|(r)|(r<<12); 985 } 986 break; 987 988 case 23: /* movh/movhu R,O(R) -> sb,sb */ 989 aclass(&p->to); 990 r = p->to.reg; 991 if(r == NREG) 992 r = o->param; 993 o1 = osr(AMOVH, p->from.reg, instoffset, r, p->scond); 994 995 o2 = oprrr(ASRL, p->scond); 996 o2 |= (8<<7)|(p->from.reg)|(REGTMP<<12); 997 998 o3 = osr(AMOVH, REGTMP, instoffset+1, r, p->scond); 999 break; 1000 1001 case 30: /* mov/movb/movbu R,L(R) */ 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 if(p->as != AMOVW) 1010 o2 |= 1<<22; 1011 break; 1012 1013 case 31: /* mov/movbu L(R),R -> lr[b] */ 1014 case 32: /* movh/movb L(R),R -> lr[b] */ 1015 o1 = omvl(p, &p->from, REGTMP); 1016 if(!o1) 1017 break; 1018 r = p->from.reg; 1019 if(r == NREG) 1020 r = o->param; 1021 o2 = olrr(REGTMP,r, p->to.reg, p->scond); 1022 if(p->as == AMOVBU || p->as == AMOVB) 1023 o2 |= 1<<22; 1024 if(o->type == 31) 1025 break; 1026 1027 o3 = oprrr(ASLL, p->scond); 1028 1029 if(p->as == AMOVBU || p->as == AMOVHU) 1030 o4 = oprrr(ASRL, p->scond); 1031 else 1032 o4 = oprrr(ASRA, p->scond); 1033 1034 r = p->to.reg; 1035 o3 |= (r)|(r<<12); 1036 o4 |= (r)|(r<<12); 1037 if(p->as == AMOVB || p->as == AMOVBU) { 1038 o3 |= (24<<7); 1039 o4 |= (24<<7); 1040 } else { 1041 o3 |= (16<<7); 1042 o4 |= (16<<7); 1043 } 1044 break; 1045 1046 case 33: /* movh/movhu R,L(R) -> sb, sb */ 1047 o1 = omvl(p, &p->to, REGTMP); 1048 if(!o1) 1049 break; 1050 r = p->to.reg; 1051 if(r == NREG) 1052 r = o->param; 1053 o2 = osrr(p->from.reg, REGTMP, r, p->scond); 1054 o2 |= (1<<22) ; 1055 1056 o3 = oprrr(ASRL, p->scond); 1057 o3 |= (8<<7)|(p->from.reg)|(p->from.reg<<12); 1058 o3 |= (1<<6); /* ROR 8 */ 1059 1060 o4 = oprrr(AADD, p->scond); 1061 o4 |= (REGTMP << 12) | (REGTMP << 16); 1062 o4 |= immrot(1); 1063 1064 o5 = osrr(p->from.reg, REGTMP,r,p->scond); 1065 o5 |= (1<<22); 1066 1067 o6 = oprrr(ASRL, p->scond); 1068 o6 |= (24<<7)|(p->from.reg)|(p->from.reg<<12); 1069 o6 |= (1<<6); /* ROL 8 */ 1070 1071 break; 1072 1073 case 34: /* mov $lacon,R */ 1074 o1 = omvl(p, &p->from, REGTMP); 1075 if(!o1) 1076 break; 1077 1078 o2 = oprrr(AADD, p->scond); 1079 o2 |= REGTMP; 1080 r = p->from.reg; 1081 if(r == NREG) 1082 r = o->param; 1083 o2 |= r << 16; 1084 if(p->to.type != D_NONE) 1085 o2 |= p->to.reg << 12; 1086 break; 1087 1088 case 35: /* mov PSR,R */ 1089 o1 = (2<<23) | (0xf<<16) | (0<<0); 1090 o1 |= (p->scond & C_SCOND) << 28; 1091 o1 |= (p->from.reg & 1) << 22; 1092 o1 |= p->to.reg << 12; 1093 break; 1094 1095 case 36: /* mov R,PSR */ 1096 o1 = (2<<23) | (0x29f<<12) | (0<<4); 1097 if(p->scond & C_FBIT) 1098 o1 ^= 0x010 << 12; 1099 o1 |= (p->scond & C_SCOND) << 28; 1100 o1 |= (p->to.reg & 1) << 22; 1101 o1 |= p->from.reg << 0; 1102 break; 1103 1104 case 37: /* mov $con,PSR */ 1105 aclass(&p->from); 1106 o1 = (2<<23) | (0x29f<<12) | (0<<4); 1107 if(p->scond & C_FBIT) 1108 o1 ^= 0x010 << 12; 1109 o1 |= (p->scond & C_SCOND) << 28; 1110 o1 |= immrot(instoffset); 1111 o1 |= (p->to.reg & 1) << 22; 1112 o1 |= p->from.reg << 0; 1113 break; 1114 1115 case 38: /* movm $con,oreg -> stm */ 1116 o1 = (0x4 << 25); 1117 o1 |= p->from.offset & 0xffff; 1118 o1 |= p->to.reg << 16; 1119 aclass(&p->to); 1120 goto movm; 1121 1122 case 39: /* movm oreg,$con -> ldm */ 1123 o1 = (0x4 << 25) | (1 << 20); 1124 o1 |= p->to.offset & 0xffff; 1125 o1 |= p->from.reg << 16; 1126 aclass(&p->from); 1127 movm: 1128 if(instoffset != 0) 1129 diag("offset must be zero in MOVM"); 1130 o1 |= (p->scond & C_SCOND) << 28; 1131 if(p->scond & C_PBIT) 1132 o1 |= 1 << 24; 1133 if(p->scond & C_UBIT) 1134 o1 |= 1 << 23; 1135 if(p->scond & C_SBIT) 1136 o1 |= 1 << 22; 1137 if(p->scond & C_WBIT) 1138 o1 |= 1 << 21; 1139 break; 1140 1141 case 40: /* swp oreg,reg,reg */ 1142 aclass(&p->from); 1143 if(instoffset != 0) 1144 diag("offset must be zero in SWP"); 1145 o1 = (0x2<<23) | (0x9<<4); 1146 if(p->as != ASWPW) 1147 o1 |= 1 << 22; 1148 o1 |= p->from.reg << 16; 1149 o1 |= p->reg << 0; 1150 o1 |= p->to.reg << 12; 1151 o1 |= (p->scond & C_SCOND) << 28; 1152 break; 1153 1154 case 41: /* rfe -> movm.s.w.u 0(r13),[r15] */ 1155 o1 = 0xe8fd8000; 1156 break; 1157 1158 case 50: /* floating point store */ 1159 v = regoff(&p->to); 1160 r = p->to.reg; 1161 if(r == NREG) 1162 r = o->param; 1163 o1 = ofsr(p->as, p->from.reg, v, r, p->scond, p); 1164 break; 1165 1166 case 51: /* floating point load */ 1167 v = regoff(&p->from); 1168 r = p->from.reg; 1169 if(r == NREG) 1170 r = o->param; 1171 o1 = ofsr(p->as, p->to.reg, v, r, p->scond, p) | (1<<20); 1172 break; 1173 1174 case 52: /* floating point store, long offset UGLY */ 1175 o1 = omvl(p, &p->to, REGTMP); 1176 if(!o1) 1177 break; 1178 r = p->to.reg; 1179 if(r == NREG) 1180 r = o->param; 1181 o2 = oprrr(AADD, p->scond) | (REGTMP << 12) | (REGTMP << 16) | r; 1182 o3 = ofsr(p->as, p->from.reg, 0, REGTMP, p->scond, p); 1183 break; 1184 1185 case 53: /* floating point load, long offset UGLY */ 1186 o1 = omvl(p, &p->from, REGTMP); 1187 if(!o1) 1188 break; 1189 r = p->from.reg; 1190 if(r == NREG) 1191 r = o->param; 1192 o2 = oprrr(AADD, p->scond) | (REGTMP << 12) | (REGTMP << 16) | r; 1193 o3 = ofsr(p->as, p->to.reg, 0, REGTMP, p->scond, p) | (1<<20); 1194 break; 1195 1196 case 54: /* floating point arith */ 1197 o1 = oprrr(p->as, p->scond); 1198 if(p->from.type == D_FCONST) { 1199 rf = chipfloat(p->from.ieee); 1200 if(rf < 0){ 1201 diag("invalid floating-point immediate\n%P", p); 1202 rf = 0; 1203 } 1204 rf |= (1<<3); 1205 } else 1206 rf = p->from.reg; 1207 rt = p->to.reg; 1208 r = p->reg; 1209 if(p->to.type == D_NONE) 1210 rt = 0; /* CMP[FD] */ 1211 else if(o1 & (1<<15)) 1212 r = 0; /* monadic */ 1213 else if(r == NREG) 1214 r = rt; 1215 o1 |= rf | (r<<16) | (rt<<12); 1216 break; 1217 1218 case 55: /* floating point fix and float */ 1219 o1 = oprrr(p->as, p->scond); 1220 rf = p->from.reg; 1221 rt = p->to.reg; 1222 if(p->to.type == D_NONE){ 1223 rt = 0; 1224 diag("to.type==D_NONE (asm/fp)"); 1225 } 1226 if(p->from.type == D_REG) 1227 o1 |= (rf<<12) | (rt<<16); 1228 else 1229 o1 |= rf | (rt<<12); 1230 break; 1231 1232 case 56: /* move to FP[CS]R */ 1233 o1 = ((p->scond & C_SCOND) << 28) | (0xe << 24) | (1<<8) | (1<<4); 1234 o1 |= ((p->to.reg+1)<<21) | (p->from.reg << 12); 1235 break; 1236 1237 case 57: /* move from FP[CS]R */ 1238 o1 = ((p->scond & C_SCOND) << 28) | (0xe << 24) | (1<<8) | (1<<4); 1239 o1 |= ((p->from.reg+1)<<21) | (p->to.reg<<12) | (1<<20); 1240 break; 1241 case 58: /* movbu R,R */ 1242 o1 = oprrr(AAND, p->scond); 1243 o1 |= immrot(0xff); 1244 rt = p->to.reg; 1245 r = p->from.reg; 1246 if(p->to.type == D_NONE) 1247 rt = 0; 1248 if(r == NREG) 1249 r = rt; 1250 o1 |= (r<<16) | (rt<<12); 1251 break; 1252 1253 case 59: /* movw/bu R<<I(R),R -> ldr indexed */ 1254 if(p->from.reg == NREG) { 1255 if(p->as != AMOVW) 1256 diag("byte MOV from shifter operand"); 1257 goto mov; 1258 } 1259 if(p->from.offset&(1<<4)) 1260 diag("bad shift in LDR"); 1261 o1 = olrr(p->from.offset, p->from.reg, p->to.reg, p->scond); 1262 if(p->as == AMOVBU) 1263 o1 |= 1<<22; 1264 break; 1265 1266 case 60: /* movb R(R),R -> ldrsb indexed */ 1267 if(p->from.reg == NREG) { 1268 diag("byte MOV from shifter operand"); 1269 goto mov; 1270 } 1271 if(p->from.offset&(~0xf)) 1272 diag("bad shift in LDRSB"); 1273 o1 = olhrr(p->from.offset, p->from.reg, p->to.reg, p->scond); 1274 o1 ^= (1<<5)|(1<<6); 1275 break; 1276 1277 case 61: /* movw/b/bu R,R<<[IR](R) -> str indexed */ 1278 if(p->to.reg == NREG) 1279 diag("MOV to shifter operand"); 1280 o1 = osrr(p->from.reg, p->to.offset, p->to.reg, p->scond); 1281 if(p->as == AMOVB || p->as == AMOVBU) 1282 o1 |= 1<<22; 1283 break; 1284 1285 case 62: /* case R -> movw R<<2(PC),PC */ 1286 o1 = olrr(p->from.reg, REGPC, REGPC, p->scond); 1287 o1 |= 2<<7; 1288 break; 1289 1290 case 63: /* bcase */ 1291 if(p->cond != P) { 1292 o1 = p->cond->pc; 1293 if(dlm) 1294 dynreloc(S, p->pc, 1); 1295 } 1296 break; 1297 1298 /* reloc ops */ 1299 case 64: /* mov/movb/movbu R,addr */ 1300 o1 = omvl(p, &p->to, REGTMP); 1301 if(!o1) 1302 break; 1303 o2 = osr(p->as, p->from.reg, 0, REGTMP, p->scond); 1304 break; 1305 1306 case 65: /* mov/movbu addr,R */ 1307 case 66: /* movh/movhu/movb addr,R */ 1308 o1 = omvl(p, &p->from, REGTMP); 1309 if(!o1) 1310 break; 1311 o2 = olr(0, REGTMP, p->to.reg, p->scond); 1312 if(p->as == AMOVBU || p->as == AMOVB) 1313 o2 |= 1<<22; 1314 if(o->type == 65) 1315 break; 1316 1317 o3 = oprrr(ASLL, p->scond); 1318 1319 if(p->as == AMOVBU || p->as == AMOVHU) 1320 o4 = oprrr(ASRL, p->scond); 1321 else 1322 o4 = oprrr(ASRA, p->scond); 1323 1324 r = p->to.reg; 1325 o3 |= (r)|(r<<12); 1326 o4 |= (r)|(r<<12); 1327 if(p->as == AMOVB || p->as == AMOVBU) { 1328 o3 |= (24<<7); 1329 o4 |= (24<<7); 1330 } else { 1331 o3 |= (16<<7); 1332 o4 |= (16<<7); 1333 } 1334 break; 1335 1336 case 67: /* movh/movhu R,addr -> sb, sb */ 1337 o1 = omvl(p, &p->to, REGTMP); 1338 if(!o1) 1339 break; 1340 o2 = osr(p->as, p->from.reg, 0, REGTMP, p->scond); 1341 1342 o3 = oprrr(ASRL, p->scond); 1343 o3 |= (8<<7)|(p->from.reg)|(p->from.reg<<12); 1344 o3 |= (1<<6); /* ROR 8 */ 1345 1346 o4 = oprrr(AADD, p->scond); 1347 o4 |= (REGTMP << 12) | (REGTMP << 16); 1348 o4 |= immrot(1); 1349 1350 o5 = osr(p->as, p->from.reg, 0, REGTMP, p->scond); 1351 1352 o6 = oprrr(ASRL, p->scond); 1353 o6 |= (24<<7)|(p->from.reg)|(p->from.reg<<12); 1354 o6 |= (1<<6); /* ROL 8 */ 1355 break; 1356 1357 case 68: /* floating point store -> ADDR */ 1358 o1 = omvl(p, &p->to, REGTMP); 1359 if(!o1) 1360 break; 1361 o2 = ofsr(p->as, p->from.reg, 0, REGTMP, p->scond, p); 1362 break; 1363 1364 case 69: /* floating point load <- ADDR */ 1365 o1 = omvl(p, &p->from, REGTMP); 1366 if(!o1) 1367 break; 1368 o2 = ofsr(p->as, p->to.reg, 0, REGTMP, p->scond, p) | (1<<20); 1369 break; 1370 1371 /* ArmV4 ops: */ 1372 case 70: /* movh/movhu R,O(R) -> strh */ 1373 aclass(&p->to); 1374 r = p->to.reg; 1375 if(r == NREG) 1376 r = o->param; 1377 o1 = oshr(p->from.reg, instoffset, r, p->scond); 1378 break; 1379 case 71: /* movb/movh/movhu O(R),R -> ldrsb/ldrsh/ldrh */ 1380 aclass(&p->from); 1381 r = p->from.reg; 1382 if(r == NREG) 1383 r = o->param; 1384 o1 = olhr(instoffset, r, p->to.reg, p->scond); 1385 if(p->as == AMOVB) 1386 o1 ^= (1<<5)|(1<<6); 1387 else if(p->as == AMOVH) 1388 o1 ^= (1<<6); 1389 break; 1390 case 72: /* movh/movhu R,L(R) -> strh */ 1391 o1 = omvl(p, &p->to, REGTMP); 1392 if(!o1) 1393 break; 1394 r = p->to.reg; 1395 if(r == NREG) 1396 r = o->param; 1397 o2 = oshrr(p->from.reg, REGTMP,r, p->scond); 1398 break; 1399 case 73: /* movb/movh/movhu L(R),R -> ldrsb/ldrsh/ldrh */ 1400 o1 = omvl(p, &p->from, REGTMP); 1401 if(!o1) 1402 break; 1403 r = p->from.reg; 1404 if(r == NREG) 1405 r = o->param; 1406 o2 = olhrr(REGTMP, r, p->to.reg, p->scond); 1407 if(p->as == AMOVB) 1408 o2 ^= (1<<5)|(1<<6); 1409 else if(p->as == AMOVH) 1410 o2 ^= (1<<6); 1411 break; 1412 case 74: /* bx $I */ 1413 #ifdef CALLEEBX 1414 diag("bx $i case (arm)"); 1415 #endif 1416 if(!seenthumb) 1417 diag("ABX $I and seenthumb==0"); 1418 v = p->cond->pc; 1419 if(p->to.sym->thumb) 1420 v |= 1; // T bit 1421 o1 = olr(8, REGPC, REGTMP, p->scond&C_SCOND); // mov 8(PC), Rtmp 1422 o2 = oprrr(AADD, p->scond) | immrot(8) | (REGPC<<16) | (REGLINK<<12); // add 8,PC, LR 1423 o3 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | REGTMP; // bx Rtmp 1424 o4 = opbra(AB, 14); // B over o6 1425 o5 = v; 1426 break; 1427 case 75: /* bx O(R) */ 1428 aclass(&p->to); 1429 if(instoffset != 0) 1430 diag("non-zero offset in ABX"); 1431 /* 1432 o1 = oprrr(AADD, p->scond) | immrot(0) | (REGPC<<16) | (REGLINK<<12); // mov PC, LR 1433 o2 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | p->to.reg; // BX R 1434 */ 1435 // p->to.reg may be REGLINK 1436 o1 = oprrr(AADD, p->scond); 1437 o1 |= immrot(instoffset); 1438 o1 |= p->to.reg << 16; 1439 o1 |= REGTMP << 12; 1440 o2 = oprrr(AADD, p->scond) | immrot(0) | (REGPC<<16) | (REGLINK<<12); // mov PC, LR 1441 o3 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | REGTMP; // BX Rtmp 1442 break; 1443 case 76: /* bx O(R) when returning from fn*/ 1444 if(!seenthumb) 1445 diag("ABXRET and seenthumb==0"); 1446 aclass(&p->to); 1447 // print("ARM BXRET %d(R%d)\n", instoffset, p->to.reg); 1448 if(instoffset != 0) 1449 diag("non-zero offset in ABXRET"); 1450 // o1 = olr(instoffset, p->to.reg, REGTMP, p->scond); // mov O(R), Rtmp 1451 o1 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | p->to.reg; // BX R 1452 break; 1453 } 1454 1455 v = p->pc; 1456 switch(o->size) { 1457 default: 1458 if(debug['a']) 1459 Bprint(&bso, " %.8lux:\t\t%P\n", v, p); 1460 break; 1461 case 4: 1462 if(debug['a']) 1463 Bprint(&bso, " %.8lux: %.8lux\t%P\n", v, o1, p); 1464 lputl(o1); 1465 break; 1466 case 8: 1467 if(debug['a']) 1468 Bprint(&bso, " %.8lux: %.8lux %.8lux%P\n", v, o1, o2, p); 1469 lputl(o1); 1470 lputl(o2); 1471 break; 1472 case 12: 1473 if(debug['a']) 1474 Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux%P\n", v, o1, o2, o3, p); 1475 lputl(o1); 1476 lputl(o2); 1477 lputl(o3); 1478 break; 1479 case 16: 1480 if(debug['a']) 1481 Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux%P\n", 1482 v, o1, o2, o3, o4, p); 1483 lputl(o1); 1484 lputl(o2); 1485 lputl(o3); 1486 lputl(o4); 1487 break; 1488 case 20: 1489 if(debug['a']) 1490 Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux%P\n", 1491 v, o1, o2, o3, o4, o5, p); 1492 lputl(o1); 1493 lputl(o2); 1494 lputl(o3); 1495 lputl(o4); 1496 lputl(o5); 1497 break; 1498 case 24: 1499 if(debug['a']) 1500 Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux%P\n", 1501 v, o1, o2, o3, o4, o5, o6, p); 1502 lputl(o1); 1503 lputl(o2); 1504 lputl(o3); 1505 lputl(o4); 1506 lputl(o5); 1507 lputl(o6); 1508 break; 1509 } 1510 } 1511 1512 long 1513 oprrr(int a, int sc) 1514 { 1515 long o; 1516 1517 o = (sc & C_SCOND) << 28; 1518 if(sc & C_SBIT) 1519 o |= 1 << 20; 1520 if(sc & (C_PBIT|C_WBIT)) 1521 diag(".P/.W on dp instruction"); 1522 switch(a) { 1523 case AMULU: 1524 case AMUL: return o | (0x0<<21) | (0x9<<4); 1525 case AMULA: return o | (0x1<<21) | (0x9<<4); 1526 case AMULLU: return o | (0x4<<21) | (0x9<<4); 1527 case AMULL: return o | (0x6<<21) | (0x9<<4); 1528 case AMULALU: return o | (0x5<<21) | (0x9<<4); 1529 case AMULAL: return o | (0x7<<21) | (0x9<<4); 1530 case AAND: return o | (0x0<<21); 1531 case AEOR: return o | (0x1<<21); 1532 case ASUB: return o | (0x2<<21); 1533 case ARSB: return o | (0x3<<21); 1534 case AADD: return o | (0x4<<21); 1535 case AADC: return o | (0x5<<21); 1536 case ASBC: return o | (0x6<<21); 1537 case ARSC: return o | (0x7<<21); 1538 case ATST: return o | (0x8<<21) | (1<<20); 1539 case ATEQ: return o | (0x9<<21) | (1<<20); 1540 case ACMP: return o | (0xa<<21) | (1<<20); 1541 case ACMN: return o | (0xb<<21) | (1<<20); 1542 case AORR: return o | (0xc<<21); 1543 case AMOVW: return o | (0xd<<21); 1544 case ABIC: return o | (0xe<<21); 1545 case AMVN: return o | (0xf<<21); 1546 case ASLL: return o | (0xd<<21) | (0<<5); 1547 case ASRL: return o | (0xd<<21) | (1<<5); 1548 case ASRA: return o | (0xd<<21) | (2<<5); 1549 case ASWI: return o | (0xf<<24); 1550 1551 case AADDD: return o | (0xe<<24) | (0x0<<20) | (1<<8) | (1<<7); 1552 case AADDF: return o | (0xe<<24) | (0x0<<20) | (1<<8); 1553 case AMULD: return o | (0xe<<24) | (0x1<<20) | (1<<8) | (1<<7); 1554 case AMULF: return o | (0xe<<24) | (0x1<<20) | (1<<8); 1555 case ASUBD: return o | (0xe<<24) | (0x2<<20) | (1<<8) | (1<<7); 1556 case ASUBF: return o | (0xe<<24) | (0x2<<20) | (1<<8); 1557 case ADIVD: return o | (0xe<<24) | (0x4<<20) | (1<<8) | (1<<7); 1558 case ADIVF: return o | (0xe<<24) | (0x4<<20) | (1<<8); 1559 case ACMPD: 1560 case ACMPF: return o | (0xe<<24) | (0x9<<20) | (0xF<<12) | (1<<8) | (1<<4); /* arguably, ACMPF should expand to RNDF, CMPD */ 1561 1562 case AMOVF: 1563 case AMOVDF: return o | (0xe<<24) | (0x0<<20) | (1<<15) | (1<<8); 1564 case AMOVD: 1565 case AMOVFD: return o | (0xe<<24) | (0x0<<20) | (1<<15) | (1<<8) | (1<<7); 1566 1567 case AMOVWF: return o | (0xe<<24) | (0<<20) | (1<<8) | (1<<4); 1568 case AMOVWD: return o | (0xe<<24) | (0<<20) | (1<<8) | (1<<4) | (1<<7); 1569 case AMOVFW: return o | (0xe<<24) | (1<<20) | (1<<8) | (1<<4); 1570 case AMOVDW: return o | (0xe<<24) | (1<<20) | (1<<8) | (1<<4) | (1<<7); 1571 } 1572 diag("bad rrr %d", a); 1573 prasm(curp); 1574 return 0; 1575 } 1576 1577 long 1578 opbra(int a, int sc) 1579 { 1580 1581 if(sc & (C_SBIT|C_PBIT|C_WBIT)) 1582 diag(".S/.P/.W on bra instruction"); 1583 sc &= C_SCOND; 1584 if(a == ABL) 1585 return (sc<<28)|(0x5<<25)|(0x1<<24); 1586 if(sc != 0xe) 1587 diag(".COND on bcond instruction"); 1588 switch(a) { 1589 case ABEQ: return (0x0<<28)|(0x5<<25); 1590 case ABNE: return (0x1<<28)|(0x5<<25); 1591 case ABCS: return (0x2<<28)|(0x5<<25); 1592 case ABHS: return (0x2<<28)|(0x5<<25); 1593 case ABCC: return (0x3<<28)|(0x5<<25); 1594 case ABLO: return (0x3<<28)|(0x5<<25); 1595 case ABMI: return (0x4<<28)|(0x5<<25); 1596 case ABPL: return (0x5<<28)|(0x5<<25); 1597 case ABVS: return (0x6<<28)|(0x5<<25); 1598 case ABVC: return (0x7<<28)|(0x5<<25); 1599 case ABHI: return (0x8<<28)|(0x5<<25); 1600 case ABLS: return (0x9<<28)|(0x5<<25); 1601 case ABGE: return (0xa<<28)|(0x5<<25); 1602 case ABLT: return (0xb<<28)|(0x5<<25); 1603 case ABGT: return (0xc<<28)|(0x5<<25); 1604 case ABLE: return (0xd<<28)|(0x5<<25); 1605 case AB: return (0xe<<28)|(0x5<<25); 1606 } 1607 diag("bad bra %A", a); 1608 prasm(curp); 1609 return 0; 1610 } 1611 1612 long 1613 olr(long v, int b, int r, int sc) 1614 { 1615 long o; 1616 1617 if(sc & C_SBIT) 1618 diag(".S on LDR/STR instruction"); 1619 o = (sc & C_SCOND) << 28; 1620 if(!(sc & C_PBIT)) 1621 o |= 1 << 24; 1622 if(!(sc & C_UBIT)) 1623 o |= 1 << 23; 1624 if(sc & C_WBIT) 1625 o |= 1 << 21; 1626 o |= (0x1<<26) | (1<<20); 1627 if(v < 0) { 1628 v = -v; 1629 o ^= 1 << 23; 1630 } 1631 if(v >= (1<<12)) 1632 diag("literal span too large: %d (R%d)\n%P", v, b, PP); 1633 o |= v; 1634 o |= b << 16; 1635 o |= r << 12; 1636 return o; 1637 } 1638 1639 long 1640 olhr(long v, int b, int r, int sc) 1641 { 1642 long o; 1643 1644 if(sc & C_SBIT) 1645 diag(".S on LDRH/STRH instruction"); 1646 o = (sc & C_SCOND) << 28; 1647 if(!(sc & C_PBIT)) 1648 o |= 1 << 24; 1649 if(sc & C_WBIT) 1650 o |= 1 << 21; 1651 o |= (1<<23) | (1<<20)|(0xb<<4); 1652 if(v < 0) { 1653 v = -v; 1654 o ^= 1 << 23; 1655 } 1656 if(v >= (1<<8)) 1657 diag("literal span too large: %d (R%d)\n%P", v, b, PP); 1658 o |= (v&0xf)|((v>>4)<<8)|(1<<22); 1659 o |= b << 16; 1660 o |= r << 12; 1661 return o; 1662 } 1663 1664 long 1665 osr(int a, int r, long v, int b, int sc) 1666 { 1667 long o; 1668 1669 o = olr(v, b, r, sc) ^ (1<<20); 1670 if(a != AMOVW) 1671 o |= 1<<22; 1672 return o; 1673 } 1674 1675 long 1676 oshr(int r, long v, int b, int sc) 1677 { 1678 long o; 1679 1680 o = olhr(v, b, r, sc) ^ (1<<20); 1681 return o; 1682 } 1683 1684 1685 long 1686 osrr(int r, int i, int b, int sc) 1687 { 1688 1689 return olr(i, b, r, sc) ^ ((1<<25) | (1<<20)); 1690 } 1691 1692 long 1693 oshrr(int r, int i, int b, int sc) 1694 { 1695 return olhr(i, b, r, sc) ^ ((1<<22) | (1<<20)); 1696 } 1697 1698 long 1699 olrr(int i, int b, int r, int sc) 1700 { 1701 1702 return olr(i, b, r, sc) ^ (1<<25); 1703 } 1704 1705 long 1706 olhrr(int i, int b, int r, int sc) 1707 { 1708 return olhr(i, b, r, sc) ^ (1<<22); 1709 } 1710 1711 long 1712 ofsr(int a, int r, long v, int b, int sc, Prog *p) 1713 { 1714 long o; 1715 1716 if(sc & C_SBIT) 1717 diag(".S on FLDR/FSTR instruction"); 1718 o = (sc & C_SCOND) << 28; 1719 if(!(sc & C_PBIT)) 1720 o |= 1 << 24; 1721 if(sc & C_WBIT) 1722 o |= 1 << 21; 1723 o |= (6<<25) | (1<<24) | (1<<23); 1724 if(v < 0) { 1725 v = -v; 1726 o ^= 1 << 23; 1727 } 1728 if(v & 3) 1729 diag("odd offset for floating point op: %d\n%P", v, p); 1730 else if(v >= (1<<10)) 1731 diag("literal span too large: %d\n%P", v, p); 1732 o |= (v>>2) & 0xFF; 1733 o |= b << 16; 1734 o |= r << 12; 1735 o |= 1 << 8; 1736 1737 switch(a) { 1738 default: 1739 diag("bad fst %A", a); 1740 case AMOVD: 1741 o |= 1<<15; 1742 case AMOVF: 1743 break; 1744 } 1745 return o; 1746 } 1747 1748 long 1749 omvl(Prog *p, Adr *a, int dr) 1750 { 1751 long v, o1; 1752 if(!p->cond) { 1753 aclass(a); 1754 v = immrot(~instoffset); 1755 if(v == 0) { 1756 diag("missing literal"); 1757 prasm(p); 1758 return 0; 1759 } 1760 o1 = oprrr(AMVN, p->scond&C_SCOND); 1761 o1 |= v; 1762 o1 |= dr << 12; 1763 } else { 1764 v = p->cond->pc - p->pc - 8; 1765 o1 = olr(v, REGPC, dr, p->scond&C_SCOND); 1766 } 1767 return o1; 1768 } 1769 1770 static Ieee chipfloats[] = { 1771 {0x00000000, 0x00000000}, /* 0 */ 1772 {0x00000000, 0x3ff00000}, /* 1 */ 1773 {0x00000000, 0x40000000}, /* 2 */ 1774 {0x00000000, 0x40080000}, /* 3 */ 1775 {0x00000000, 0x40100000}, /* 4 */ 1776 {0x00000000, 0x40140000}, /* 5 */ 1777 {0x00000000, 0x3fe00000}, /* .5 */ 1778 {0x00000000, 0x40240000}, /* 10 */ 1779 }; 1780 1781 int 1782 chipfloat(Ieee *e) 1783 { 1784 Ieee *p; 1785 int n; 1786 1787 for(n = sizeof(chipfloats)/sizeof(chipfloats[0]); --n >= 0;){ 1788 p = &chipfloats[n]; 1789 if(p->l == e->l && p->h == e->h) 1790 return n; 1791 } 1792 return -1; 1793 } 1794