1 #include "l.h" 2 3 long OFFSET; 4 5 static Prog *PP; 6 7 long 8 entryvalue(void) 9 { 10 char *a; 11 Sym *s; 12 13 a = INITENTRY; 14 if(*a >= '0' && *a <= '9') 15 return atolwhex(a); 16 s = lookup(a, 0); 17 if(s->type == 0) 18 return INITTEXT; 19 switch(s->type) { 20 case STEXT: 21 case SLEAF: 22 break; 23 case SDATA: 24 if(dlm) 25 return s->value+INITDAT; 26 default: 27 diag("entry not text: %s", s->name); 28 } 29 return s->value; 30 } 31 32 void 33 asmb(void) 34 { 35 Prog *p; 36 long t, etext; 37 Optab *o; 38 39 if(debug['v']) 40 Bprint(&bso, "%5.2f asm\n", cputime()); 41 Bflush(&bso); 42 OFFSET = HEADR; 43 seek(cout, OFFSET, 0); 44 pc = INITTEXT; 45 for(p = firstp; p != P; p = p->link) { 46 if(p->as == ATEXT) { 47 curtext = p; 48 autosize = p->to.offset + 4; 49 } 50 if(p->pc != pc) { 51 diag("phase error %lux sb %lux", 52 p->pc, pc); 53 if(!debug['a']) 54 prasm(curp); 55 pc = p->pc; 56 } 57 curp = p; 58 o = oplook(p); /* could probably avoid this call */ 59 asmout(p, o); 60 pc += o->size; 61 } 62 63 if(debug['a']) 64 Bprint(&bso, "\n"); 65 Bflush(&bso); 66 cflush(); 67 68 /* output strings in text segment */ 69 etext = INITTEXT + textsize; 70 for(t = pc; t < etext; t += sizeof(buf)-100) { 71 if(etext-t > sizeof(buf)-100) 72 datblk(t, sizeof(buf)-100, 1); 73 else 74 datblk(t, etext-t, 1); 75 } 76 77 curtext = P; 78 switch(HEADTYPE) { 79 case 0: 80 case 1: 81 case 2: 82 case 5: 83 case 7: 84 OFFSET = HEADR+textsize; 85 seek(cout, OFFSET, 0); 86 break; 87 case 3: 88 case 6: /* no header, padded segments */ 89 OFFSET = rnd(HEADR+textsize, 4096); 90 seek(cout, OFFSET, 0); 91 break; 92 } 93 if(dlm){ 94 char buf[8]; 95 96 write(cout, buf, INITDAT-textsize); 97 textsize = INITDAT; 98 } 99 for(t = 0; t < datsize; t += sizeof(buf)-100) { 100 if(datsize-t > sizeof(buf)-100) 101 datblk(t, sizeof(buf)-100, 0); 102 else 103 datblk(t, datsize-t, 0); 104 } 105 106 symsize = 0; 107 lcsize = 0; 108 if(!debug['s']) { 109 if(debug['v']) 110 Bprint(&bso, "%5.2f sym\n", cputime()); 111 Bflush(&bso); 112 switch(HEADTYPE) { 113 case 0: 114 case 1: 115 case 4: 116 case 5: 117 debug['s'] = 1; 118 break; 119 case 2: 120 OFFSET = HEADR+textsize+datsize; 121 seek(cout, OFFSET, 0); 122 break; 123 case 3: 124 case 6: /* no header, padded segments */ 125 OFFSET += rnd(datsize, 4096); 126 seek(cout, OFFSET, 0); 127 break; 128 case 7: 129 break; 130 } 131 if(!debug['s']) 132 asmsym(); 133 if(debug['v']) 134 Bprint(&bso, "%5.2f pc\n", cputime()); 135 Bflush(&bso); 136 if(!debug['s']) 137 asmlc(); 138 if(dlm) 139 asmdyn(); 140 cflush(); 141 } 142 else if(dlm){ 143 seek(cout, HEADR+textsize+datsize, 0); 144 asmdyn(); 145 cflush(); 146 } 147 148 if(debug['v']) 149 Bprint(&bso, "%5.2f header\n", cputime()); 150 Bflush(&bso); 151 OFFSET = 0; 152 seek(cout, OFFSET, 0); 153 switch(HEADTYPE) { 154 case 0: /* no header */ 155 case 6: /* no header, padded segments */ 156 break; 157 case 1: /* aif for risc os */ 158 lputl(0xe1a00000); /* NOP - decompress code */ 159 lputl(0xe1a00000); /* NOP - relocation code */ 160 lputl(0xeb000000 + 12); /* BL - zero init code */ 161 lputl(0xeb000000 + 162 (entryvalue() 163 - INITTEXT 164 + HEADR 165 - 12 166 - 8) / 4); /* BL - entry code */ 167 168 lputl(0xef000011); /* SWI - exit code */ 169 lputl(textsize+HEADR); /* text size */ 170 lputl(datsize); /* data size */ 171 lputl(0); /* sym size */ 172 173 lputl(bsssize); /* bss size */ 174 lputl(0); /* sym type */ 175 lputl(INITTEXT-HEADR); /* text addr */ 176 lputl(0); /* workspace - ignored */ 177 178 lputl(32); /* addr mode / data addr flag */ 179 lputl(0); /* data addr */ 180 for(t=0; t<2; t++) 181 lputl(0); /* reserved */ 182 183 for(t=0; t<15; t++) 184 lputl(0xe1a00000); /* NOP - zero init code */ 185 lputl(0xe1a0f00e); /* B (R14) - zero init return */ 186 break; 187 case 2: /* plan 9 */ 188 if(dlm) 189 lput(0x80000000|0x647); /* magic */ 190 else 191 lput(0x647); /* magic */ 192 lput(textsize); /* sizes */ 193 lput(datsize); 194 lput(bsssize); 195 lput(symsize); /* nsyms */ 196 lput(entryvalue()); /* va of entry */ 197 lput(0L); 198 lput(lcsize); 199 break; 200 case 3: /* boot for NetBSD */ 201 lput((143<<16)|0413); /* magic */ 202 lputl(rnd(HEADR+textsize, 4096)); 203 lputl(rnd(datsize, 4096)); 204 lputl(bsssize); 205 lputl(symsize); /* nsyms */ 206 lputl(entryvalue()); /* va of entry */ 207 lputl(0L); 208 lputl(0L); 209 break; 210 case 4: /* boot for IXP1200 */ 211 break; 212 case 5: /* boot for ipaq */ 213 lputl(0xe3300000); /* nop */ 214 lputl(0xe3300000); /* nop */ 215 lputl(0xe3300000); /* nop */ 216 lputl(0xe3300000); /* nop */ 217 break; 218 case 7: /* elf */ 219 debug['S'] = 1; /* symbol table */ 220 elf32(ARM, ELFDATA2LSB, 0, nil); 221 break; 222 } 223 cflush(); 224 } 225 226 void 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 238 cput(int c) 239 { 240 cbp[0] = c; 241 cbp++; 242 cbc--; 243 if(cbc <= 0) 244 cflush(); 245 } 246 247 void 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 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 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 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 300 llput(vlong v) 301 { 302 lput(v>>32); 303 lput(v); 304 } 305 306 void 307 llputl(vlong v) 308 { 309 lputl(v); 310 lputl(v>>32); 311 } 312 313 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 1682 olhrr(int i, int b, int r, int sc) 1683 { 1684 return olhr(i, b, r, sc) ^ (1<<22); 1685 } 1686 1687 long 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 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 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 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