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