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