|
|
1.1 ! root 1: /* ! 2: * The routines in this file assemble buffered code ! 3: * and write the code to the output file. ! 4: * This version is for the SMALL and LARGE models of segmentation. ! 5: */ ! 6: ! 7: #ifdef vax ! 8: #include "INC$LIB:cc2.h" ! 9: #else ! 10: #include "cc2.h" ! 11: #endif ! 12: ! 13: #define W 0x01 /* W (word) bit */ ! 14: #define D 0x02 /* D (direction) bit */ ! 15: #define ESC 0xD8 /* Escape */ ! 16: #define WAIT 0x9B /* Wait */ ! 17: ! 18: static ADDRESS pc; /* Current assembly pc */ ! 19: static ADDRESS pcdot[NSEG]; /* Working copy of seg '.' fields */ ! 20: static int pcseg; /* Current segment */ ! 21: static int pass; /* Pass flag; only 1 emits code */ ! 22: ! 23: extern int hasfloat; /* function uses floating point */ ! 24: ! 25: /* ! 26: * Driving routine. ! 27: * Run pass 0 of the assembly to get sizes. ! 28: * All jumps are assumed to be short. ! 29: * Fix up any that don't reach. ! 30: * Run the second assembly pass to generate the final code. ! 31: */ ! 32: genfunc() ! 33: { ! 34: register INS *ip1, *ip2; ! 35: register int i; ! 36: ! 37: pc = dot; ! 38: pass = 0; ! 39: pcseg = dotseg; ! 40: for (i=0; i<NSEG; ++i) ! 41: pcdot[i] = seg[i].s_dot; ! 42: ip1 = ins.i_fp; ! 43: while (ip1 != &ins) { ! 44: assemble(ip1); ! 45: ip1 = ip1->i_fp; ! 46: } ! 47: sdi(); ! 48: pc = dot; ! 49: pass = 1; ! 50: pcseg = dotseg; ! 51: for (i=0; i<NSEG; ++i) ! 52: pcdot[i] = seg[i].s_dot; ! 53: ip1 = ins.i_fp; ! 54: while (ip1 != &ins) { ! 55: asmdbgt(ip1); ! 56: if (isvariant(VASM)) ! 57: unassemble(ip1); ! 58: else ! 59: assemble(ip1); ! 60: ip2 = ip1->i_fp; ! 61: free((char *) ip1); ! 62: ip1 = ip2; ! 63: } ! 64: asmdbgt(&ins); ! 65: } ! 66: ! 67: /* ! 68: * Generate code for a single instruction. ! 69: * Used to compile external data definitions, etc. ! 70: */ ! 71: genins(ip) ! 72: register INS *ip; ! 73: { ! 74: register int i; ! 75: ! 76: for (pass=0; pass!=2; ++pass) { ! 77: pc = dot; ! 78: pcseg = dotseg; ! 79: for (i=0; i<NSEG; ++i) ! 80: pcdot[i] = seg[i].s_dot; ! 81: if (isvariant(VASM) && pass != 0) { ! 82: if (ip->i_type != LINE ! 83: || isvariant(VLINES)) ! 84: unassemble(ip); ! 85: } else ! 86: assemble(ip); ! 87: } ! 88: } ! 89: ! 90: /* ! 91: * This function fixes up the span dependent instructions. ! 92: * The only case on the iAPX-86 is the jump, which has limited range. ! 93: * There is nothing to be done with the adjustable displacements, ! 94: * bacause these are always absolute and do not change. ! 95: */ ! 96: sdi() ! 97: { ! 98: register INS *ip1, *ip2; ! 99: register SYM *sp; ! 100: register int bump, changes; ! 101: SIGNEDADDRESS disp; ! 102: ! 103: do { ! 104: changes = 0; ! 105: ip1 = ins.i_fp; ! 106: while (ip1 != &ins) { ! 107: if (isoptjump(ip1)) { ! 108: if ((sp=ip1->i_sp) == NULL) ! 109: cbotch("sdi"); ! 110: if (ip1->i_pcseg != sp->s_seg) ! 111: cbotch("x seg #1"); ! 112: disp = sp->s_value-ip1->i_pc-2; ! 113: if (disp<-128 || disp>127) { ! 114: ip1->i_long = 1; ! 115: changes = 1; ! 116: bump = 1; ! 117: if (ip1->i_rel != ZJMP) ! 118: bump = 3; ! 119: ip2 = ip1->i_fp; ! 120: while (ip2 != &ins) { ! 121: sdibump(ip1, ip2, bump); ! 122: ip2 = ip2->i_fp; ! 123: } ! 124: } ! 125: } ! 126: ip1 = ip1->i_fp; ! 127: } ! 128: } while (changes); ! 129: } ! 130: ! 131: /* ! 132: * This routine performs the nitty gritty ! 133: * of bumping an instruction to a higher address because ! 134: * an sdi changed from short to long. ! 135: * The 'ip1' argument is a pointer to the INS of the jump. ! 136: * The 'ip2' argument is the node to be bumped by 'bump' bytes. ! 137: * Only labels and code in the same segment as the 'ip1' node are adjusted. ! 138: */ ! 139: sdibump(ip1, ip2, bump) ! 140: register INS *ip1; ! 141: register INS *ip2; ! 142: { ! 143: register int type; ! 144: register SYM *sp; ! 145: ! 146: if ((type=ip2->i_type) == LLABEL) { ! 147: if ((sp=ip2->i_sp) == NULL) ! 148: cbotch("sdibump"); ! 149: if (sp->s_seg == ip1->i_pcseg) ! 150: sp->s_value += bump; ! 151: } else if (type==JUMP || type==CODE) { ! 152: if (ip2->i_pcseg == ip1->i_pcseg) ! 153: ip2->i_pc += bump; ! 154: } ! 155: } ! 156: ! 157: /* ! 158: * This routine checks if a node is an optimizable short jump. ! 159: * The node must be a jump, ! 160: * it must be short and it must either be the unconditional ! 161: * jump or one of the jumps that has a reverse. ! 162: */ ! 163: isoptjump(ip1) ! 164: register INS *ip1; ! 165: { ! 166: register int rel; ! 167: ! 168: if (ip1->i_type==JUMP && ip1->i_long==0) { ! 169: rel = ip1->i_rel; ! 170: if (rel!=ZJCXZ && rel!=ZLOOP && rel!=ZLOOPE && rel!=ZLOOPNE) ! 171: return (1); ! 172: } ! 173: return (0); ! 174: } ! 175: ! 176: /* ! 177: * Assemble a line. ! 178: * If pass 1 the binary goes straight out. ! 179: * The ip1 argument points to the INS node that is to be assembled. ! 180: */ ! 181: assemble(ip1) ! 182: register INS *ip1; ! 183: { ! 184: SIGNEDADDRESS disp; ! 185: int opbits; ! 186: int escape; ! 187: OPINFO *opinfop; ! 188: int opcode; ! 189: SYM *sp; ! 190: int ostyle; ! 191: AFIELD a1; ! 192: int prefix; ! 193: int m1, m2, regm, rn; ! 194: int shortflag; ! 195: sizeof_t length; ! 196: int segreg; ! 197: int m3; ! 198: ! 199: switch (ip1->i_type) { ! 200: ! 201: case ENTER: ! 202: pcdot[pcseg] = pc; ! 203: pcseg = ip1->i_seg; ! 204: pc = pcdot[pcseg]; ! 205: if (pass != 0) ! 206: genseg(pcseg); ! 207: break; ! 208: ! 209: case BLOCK: ! 210: if ((length=ip1->i_len) != 0) { ! 211: if (pcseg == SBSS) { ! 212: pc += length; ! 213: if (pass != 0) ! 214: dot += length; ! 215: } else { ! 216: #if 0 /* i8086 outnzb() not implemented yet */ ! 217: outnzb(length); ! 218: #else ! 219: do { ! 220: asmab(0); ! 221: } while (--length); ! 222: #endif ! 223: } ! 224: } ! 225: break; ! 226: ! 227: case ALIGN: ! 228: if ((pc&01) != 0) { ! 229: if (pcseg == SBSS) { ! 230: ++pc; ! 231: if (pass != 0) ! 232: ++dot; ! 233: } else ! 234: asmab(0); ! 235: } ! 236: break; ! 237: ! 238: case JUMP: ! 239: ip1->i_pc = pc; ! 240: ip1->i_pcseg = pcseg; ! 241: if ((sp=ip1->i_sp) == NULL) { ! 242: sp = llookup(ip1->i_labno, 0); ! 243: ip1->i_sp = sp; ! 244: } ! 245: if (pass != 0) { ! 246: if (sp==NULL || (sp->s_flag&S_DEF)==0) ! 247: cbotch("undef"); ! 248: if (ip1->i_long == 0) { ! 249: if (sp->s_seg != ip1->i_pcseg) ! 250: cbotch("x seg #2"); ! 251: disp = sp->s_value - pc - 2; ! 252: if (disp<-128 || disp>127) ! 253: cbotch("reach, disp=%d", disp); ! 254: } ! 255: } ! 256: opbits = opinfo[ip1->i_rel].op_opcode; ! 257: if (ip1->i_long == 0) { ! 258: asmab(opbits); ! 259: asmab(disp); ! 260: } else { ! 261: if (ip1->i_rel != ZJMP) { ! 262: asmab(opbits ^ 01); ! 263: asmab(03); ! 264: } ! 265: asmab(0xE9); /* Jump */ ! 266: a1.a_mode = A_DIR; ! 267: a1.a_sp = sp; ! 268: a1.a_value = 0; ! 269: asmxw(&a1, 1); ! 270: } ! 271: break; ! 272: ! 273: case LLABEL: ! 274: if ((sp=ip1->i_sp) == NULL) { ! 275: sp = llookup(ip1->i_labno, 1); ! 276: ip1->i_sp = sp; ! 277: } ! 278: sp->s_seg = pcseg; ! 279: sp->s_value = pc; ! 280: break; ! 281: ! 282: case LLLINK: ! 283: if ((sp=ip1->i_sp) == NULL) { ! 284: sp = llookup(ip1->i_labno, 0); ! 285: ip1->i_sp = sp; ! 286: } ! 287: if (pass!=0 && (sp==NULL || (sp->s_flag&S_DEF)==0)) ! 288: cbotch("undef"); ! 289: a1.a_mode = A_DIR; ! 290: a1.a_sp = sp; ! 291: a1.a_value = 0; ! 292: asmxw(&a1, 0); ! 293: break; ! 294: ! 295: case CODE: ! 296: ip1->i_pc = pc; ! 297: ip1->i_pcseg = pcseg; ! 298: opcode = ip1->i_op; ! 299: opinfop = &opinfo[opcode]; ! 300: opbits = opinfop->op_opcode; ! 301: switch (ostyle = opinfop->op_style) { ! 302: ! 303: case OF_INH2: ! 304: asmab(opbits); ! 305: asmab(0x0A); ! 306: break; ! 307: ! 308: case OF_INH: ! 309: asmab(opbits); ! 310: break; ! 311: ! 312: case OF_PUSH: ! 313: case OF_POP: ! 314: m1 = ip1->i_af[0].a_mode&(A_AMOD|A_PREFX); ! 315: rn = ip1->i_af[0].a_mode&A_REGM; ! 316: if (isvariant(V80186)) { ! 317: if ((ostyle == OF_PUSH) && (m1 == A_IMM)) { ! 318: if (isshort(&ip1->i_af[0])) { ! 319: asmab(0x6A); ! 320: asmxb(&ip1->i_af[0], 0); ! 321: } ! 322: else { ! 323: asmab(0x68); ! 324: asmxw(&ip1->i_af[0], 0); ! 325: } ! 326: break; ! 327: } ! 328: } ! 329: if (m1 == A_SR) { ! 330: if (ostyle == OF_PUSH) ! 331: asmab(0x06 | (rn<<3)); ! 332: else ! 333: asmab(0x07 | (rn<<3)); ! 334: break; ! 335: } ! 336: if (m1 == A_WR) { ! 337: if (ostyle == OF_PUSH) ! 338: asmab(0x50 | rn); ! 339: else ! 340: asmab(0x58 | rn); ! 341: break; ! 342: } ! 343: if (ostyle == OF_PUSH) ! 344: asmgen(0xFF, 0x30, &ip1->i_af[0]); ! 345: else ! 346: asmgen(0x8F, 0x00, &ip1->i_af[0]); ! 347: break; ! 348: ! 349: case OF_SHR: ! 350: prefix = 0xD0 | (opbits&W); ! 351: opbits &= ~W; ! 352: if (ip1->i_af[1].a_mode == A_RCL) ! 353: prefix |= 0x02; ! 354: else if ((ip1->i_af[1].a_mode&A_AMOD) != A_IMM ! 355: || (notvariant(V80186) && ip1->i_af[1].a_value != 1) ! 356: || ip1->i_af[1].a_sp != NULL) ! 357: aerr(ip1); ! 358: if (isvariant(V80186)) { ! 359: disp = ip1->i_af[1].a_value; ! 360: if ((ip1->i_af[1].a_mode != A_RCL) && (disp != 1)) { ! 361: /* 286 shift immediate */ ! 362: prefix &= 0xEF; /* Change 0xD0|W to 0xC0|W */ ! 363: asmgen(prefix, opbits, &ip1->i_af[0]); ! 364: /* Be wary of shift counts > 16 */ ! 365: asmab((disp <= 16) ? disp : 16); ! 366: break; ! 367: } ! 368: } ! 369: asmgen(prefix, opbits, &ip1->i_af[0]); ! 370: break; ! 371: ! 372: case OF_ICALL: ! 373: asmgen(0xFF, opbits, &ip1->i_af[0]); ! 374: break; ! 375: ! 376: case OF_CALL: ! 377: if ((ip1->i_af[0].a_mode&(A_AMOD|A_PREFX)) != A_DIR) ! 378: aerr(ip1); ! 379: asmab(0xE8); ! 380: asmxw(&ip1->i_af[0], 1); ! 381: break; ! 382: ! 383: case OF_XCALL: ! 384: if ((ip1->i_af[0].a_mode&(A_AMOD|A_PREFX)) != A_DIR) ! 385: aerr(ip1); ! 386: asmab(0x9A); ! 387: asmxw(&ip1->i_af[0], 0); ! 388: asmsb(&ip1->i_af[0]); ! 389: break; ! 390: ! 391: case OF_DOPS: ! 392: case OF_DOP: ! 393: m1 = ip1->i_af[0].a_mode&(A_AMOD|A_PREFX); ! 394: m2 = ip1->i_af[1].a_mode&(A_AMOD|A_PREFX); ! 395: if (m2 == A_IMM) { ! 396: shortflag = 0; ! 397: if (isalax(&ip1->i_af[0])) { ! 398: /* Test[b] */ ! 399: if (opbits == 0x85) ! 400: opbits = 0xA9; ! 401: else if (opbits == 0x84) ! 402: opbits = 0xA8; ! 403: else ! 404: opbits |= 0x04; ! 405: asmab(opbits); ! 406: } else { ! 407: /* Test[b] */ ! 408: if (opbits==0x84 || opbits==0x85) { ! 409: regm = 0; ! 410: if (opbits == 0x84) ! 411: opbits = 0xF6; ! 412: else ! 413: opbits = 0xF7; ! 414: } else { ! 415: regm = opbits & 0x38; ! 416: opbits = (opbits&W)|0x80; ! 417: if (ostyle == OF_DOPS ! 418: && isshort(&ip1->i_af[1])) { ! 419: shortflag = 1; ! 420: opbits |= 0x02; ! 421: } ! 422: } ! 423: asmgen(opbits, regm, &ip1->i_af[0]); ! 424: } ! 425: if (shortflag || (opbits&W)==0) ! 426: asmxb(&ip1->i_af[1], 0); ! 427: else ! 428: asmxw(&ip1->i_af[1], 0); ! 429: break; ! 430: } ! 431: /* To reg */ ! 432: if (m1==A_BR || m1==A_WR) { ! 433: /* Test[b] */ ! 434: if (opbits!=0x84 && opbits!=0x85) ! 435: opbits |= 0x02; /* D */ ! 436: asmgen(opbits, (ip1->i_af[0].a_mode&A_REGM)<<3, ! 437: &ip1->i_af[1]); ! 438: break; ! 439: } ! 440: /* To mem */ ! 441: asmgen(opbits, (ip1->i_af[1].a_mode&A_REGM)<<3, ! 442: &ip1->i_af[0]); ! 443: break; ! 444: ! 445: case OF_MUL3: ! 446: if (notvariant(V80186)) ! 447: aerr(ip1); ! 448: m1 = ip1->i_af[0].a_mode&(A_AMOD|A_PREFX); ! 449: m2 = ip1->i_af[1].a_mode&(A_AMOD|A_PREFX); ! 450: m3 = ip1->i_af[2].a_mode&(A_AMOD|A_PREFX); ! 451: if (m1 != A_WR || m3 != A_IMM) ! 452: aerr(ip1); ! 453: shortflag = 0; ! 454: if (isshort(&ip1->i_af[2])) { ! 455: shortflag = 1; ! 456: opbits |= 0x02; /* Change 0x69 to 0x6B */ ! 457: } ! 458: asmgen(opbits, (ip1->i_af[0].a_mode&A_REGM)<<3, &ip1->i_af[1]); ! 459: if (shortflag) ! 460: asmxb(&ip1->i_af[2], 0); ! 461: else ! 462: asmxw(&ip1->i_af[2], 0); ! 463: break; ! 464: ! 465: case OF_SOP: ! 466: m1 = ip1->i_af[0].a_mode&(A_AMOD|A_PREFX); ! 467: prefix = ((opbits<0x10)?0xFE:0xF6) | (opbits&W); ! 468: opbits &= ~W; ! 469: if (prefix==0xFF && m1==A_WR) { ! 470: asmab(0x40 | opbits | ! 471: (ip1->i_af[0].a_mode&A_REGM)); ! 472: break; ! 473: } ! 474: asmgen(prefix, opbits, &ip1->i_af[0]); ! 475: break; ! 476: ! 477: case OF_LEA: ! 478: m1 = ip1->i_af[0].a_mode&(A_AMOD|A_PREFX); ! 479: m2 = ip1->i_af[1].a_mode&A_AMOD; ! 480: if (m1!=A_WR || (m2!=A_DIR && m2!=A_X)) ! 481: aerr(ip1); ! 482: asmgen(opbits, (ip1->i_af[0].a_mode&A_REGM)<<3, ! 483: &ip1->i_af[1]); ! 484: break; ! 485: ! 486: case OF_MOV: ! 487: m1 = ip1->i_af[0].a_mode&(A_AMOD|A_PREFX); ! 488: m2 = ip1->i_af[1].a_mode&(A_AMOD|A_PREFX); ! 489: if (m2 == A_IMM) { ! 490: if (m1 == A_BR) { ! 491: asmab(0xB0 | ! 492: (ip1->i_af[0].a_mode&A_REGM)); ! 493: asmxb(&ip1->i_af[1], 0); ! 494: break; ! 495: } ! 496: if (m1 == A_WR) { ! 497: asmab(0xB8 | ! 498: (ip1->i_af[0].a_mode&A_REGM)); ! 499: asmxw(&ip1->i_af[1], 0); ! 500: break; ! 501: } ! 502: /* To mem */ ! 503: asmgen((0xC6 | (opbits&W)), 0, &ip1->i_af[0]); ! 504: if ((opbits&W) == 0) ! 505: asmxb(&ip1->i_af[1], 0); ! 506: else ! 507: asmxw(&ip1->i_af[1], 0); ! 508: break; ! 509: } ! 510: if (isalax(&ip1->i_af[0]) && m2==A_DIR) { ! 511: asmprefix(&ip1->i_af[1]); ! 512: asmab(0xA0 | (opbits&W)); ! 513: asmxw(&ip1->i_af[1], 0); ! 514: break; ! 515: } ! 516: if (m1==A_DIR && isalax(&ip1->i_af[1])) { ! 517: asmprefix(&ip1->i_af[0]); ! 518: asmab(0xA2 | (opbits&W)); ! 519: asmxw(&ip1->i_af[0], 0); ! 520: break; ! 521: } ! 522: if (m1 == A_SR) { ! 523: if (m2 != A_SR) { ! 524: asmgen(0x8E, (ip1->i_af[0].a_mode&A_REGM)<<3, ! 525: &ip1->i_af[1]); ! 526: } ! 527: else { /* Kludge MOV SR1, SR2 ! 528: * into PUSH SR2, POP SR1. ! 529: * This should not happen but ! 530: * better safe than sorry... ! 531: */ ! 532: asmab(0x06 | ((ip1->i_af[1].a_mode&A_REGM)<<3)); ! 533: asmab(0x07 | ((ip1->i_af[0].a_mode&A_REGM)<<3)); ! 534: } ! 535: } ! 536: else if (m2 == A_SR) ! 537: asmgen(0x8C, (ip1->i_af[1].a_mode&A_REGM)<<3, ! 538: &ip1->i_af[0]); ! 539: else if (m1==A_WR || m1==A_BR) ! 540: asmgen(opbits|D, ! 541: (ip1->i_af[0].a_mode&A_REGM)<<3, ! 542: &ip1->i_af[1]); ! 543: else ! 544: asmgen(opbits, ! 545: (ip1->i_af[1].a_mode&A_REGM)<<3, ! 546: &ip1->i_af[0]); ! 547: break; ! 548: ! 549: case OF_MUL: ! 550: prefix = 0xF6 | (opbits&W); ! 551: opbits &= ~W; ! 552: asmgen(prefix, opbits, &ip1->i_af[0]); ! 553: break; ! 554: ! 555: case OF_WORD: ! 556: case OF_BYTE: ! 557: case OF_LPTR: ! 558: case OF_GPTR: ! 559: if ((ip1->i_af[0].a_mode&(A_AMOD|A_PREFX)) != A_DIR) ! 560: aerr(ip1); ! 561: if (ostyle == OF_BYTE) ! 562: asmxb(&ip1->i_af[0], 0); ! 563: else { ! 564: asmxw(&ip1->i_af[0], 0); ! 565: if (ostyle == OF_GPTR) ! 566: asmsb(&ip1->i_af[0]); ! 567: } ! 568: break; ! 569: ! 570: /* ! 571: * 8087 or 80287 floating point operations. ! 572: * See comments preceding "asmfwait()" below. ! 573: */ ! 574: case OF_FWAIT: ! 575: asmfwait(); ! 576: break; ! 577: ! 578: case OF_FD9: ! 579: asmfop(0xD9, 0); ! 580: asmab(opbits); ! 581: break; ! 582: ! 583: case OF_FDD: ! 584: asmfop(0xDD, 0); ! 585: asmab(opbits); ! 586: break; ! 587: ! 588: case OF_FDE: ! 589: asmfop(0xDE, 0); ! 590: asmab(opbits); ! 591: break; ! 592: ! 593: case OF_FRM: ! 594: escape = ESC | (opbits&0x07); ! 595: if ((ip1->i_af[0].a_mode&A_PREFX) != 0) { ! 596: prefix = ip1->i_af[0].a_mode&A_PREFX; ! 597: segreg = (prefix>>8) - 1; ! 598: asmfop(0x26|(segreg<<3), prefix); ! 599: asmab(escape); ! 600: } else ! 601: asmfop(escape, 0); ! 602: asmgen(-1, opbits&0x38, &ip1->i_af[0]); ! 603: break; ! 604: ! 605: default: ! 606: cbotch("cannot assemble %d", opcode); ! 607: } ! 608: } ! 609: } ! 610: ! 611: /* ! 612: * General output. ! 613: * Understands MOD/R/M bytes and all that. ! 614: * An opcode of -1 is a flag that says don't put ! 615: * out the opcode and treat a register address field as an error. ! 616: * It is used for the 8087. ! 617: * The r field is preshifted left by 3 bits. ! 618: */ ! 619: asmgen(op, r, afp) ! 620: register AFIELD *afp; ! 621: { ! 622: SIGNEDADDRESS disp; ! 623: int mode, regm; ! 624: ! 625: if (op >= 0) { ! 626: asmprefix(afp); ! 627: asmab(op); ! 628: } ! 629: mode = afp->a_mode & A_AMOD; ! 630: regm = afp->a_mode & A_REGM; ! 631: if (mode==A_IMM || mode==A_SR) ! 632: cbotch("asmgen op=%d r=%d mode=%d regm=%d", ! 633: op, r, mode, regm); ! 634: if (mode==A_BR || mode==A_WR) { ! 635: if (op < 0) ! 636: cbotch("asmgen"); ! 637: asmab(0xC0 | r | regm); ! 638: return; ! 639: } ! 640: if (mode == A_DIR) { ! 641: asmab(0x06 | r); ! 642: asmxw(afp, 0); ! 643: return; ! 644: } ! 645: if (afp->a_sp == NULL) { ! 646: disp = afp->a_value; ! 647: if (regm!=6 && disp==0) { ! 648: asmab(r | regm); ! 649: return; ! 650: } ! 651: if (disp>=-128 && disp<=127) { ! 652: asmab(0x40 | r | regm); ! 653: asmab(disp); ! 654: return; ! 655: } ! 656: } ! 657: asmab(0x80 | r | regm); ! 658: asmxw(afp, 0); ! 659: } ! 660: ! 661: /* ! 662: * Given an address field description, ! 663: * look at the A_PREFX field of the mode and ! 664: * output an escape prefix byte, if one is required. ! 665: * The codes assigned to the segment registers have been cleverly chosen ! 666: * so that code-1 is the right number to put in the prefix byte. ! 667: */ ! 668: asmprefix(afp) ! 669: register AFIELD *afp; ! 670: { ! 671: register int segreg; ! 672: ! 673: if ((afp->a_mode&A_PREFX) != 0) { ! 674: segreg = ((afp->a_mode&A_PREFX)>>8) - 1; ! 675: asmab(0x26 | (segreg<<3)); ! 676: } ! 677: } ! 678: ! 679: /* ! 680: * Output an absolute byte. ! 681: * Toss the byte away if this is not the second pass. ! 682: * Check for compiling code into the bss segment. ! 683: */ ! 684: asmab(b) ! 685: { ! 686: if (pass != 0) { ! 687: berr(); ! 688: outab(b); ! 689: } ! 690: ++pc; ! 691: } ! 692: ! 693: /* ! 694: * Output an absolute word. ! 695: * Toss the word away if this is not the second pass. ! 696: * Check for compiling code into the bss segment. ! 697: */ ! 698: asmaw(w) ! 699: { ! 700: if (pass != 0) { ! 701: berr(); ! 702: outaw(w); ! 703: } ! 704: pc += 2; ! 705: } ! 706: ! 707: /* ! 708: * Output a general byte. ! 709: * The 'afp' argument is a pointer to an 'afield'. ! 710: * The 'flag' is true for pc relative addressing. ! 711: */ ! 712: asmxb(afp, flag) ! 713: register AFIELD *afp; ! 714: { ! 715: if (pass != 0) { ! 716: berr(); ! 717: outxb(afp->a_sp, afp->a_value, flag); ! 718: } ! 719: ++pc; ! 720: } ! 721: ! 722: /* ! 723: * Output a general word. ! 724: * The 'afp' parameter is a pointer to an 'afield'. ! 725: * The 'flag' is true for pc relative addressing. ! 726: */ ! 727: asmxw(afp, flag) ! 728: register AFIELD *afp; ! 729: { ! 730: if (pass != 0) { ! 731: berr(); ! 732: outxw(afp->a_sp, afp->a_value, flag); ! 733: } ! 734: pc += 2; ! 735: } ! 736: ! 737: /* ! 738: * Output a segment base. ! 739: */ ! 740: asmsb(afp) ! 741: register AFIELD *afp; ! 742: { ! 743: register SYM *sp; ! 744: ! 745: if (pass != 0) { ! 746: berr(); ! 747: if ((sp=afp->a_sp) == NULL) ! 748: outaw(0); ! 749: else ! 750: outsb(sp); ! 751: } ! 752: pc += 2; ! 753: } ! 754: ! 755: /* ! 756: * Notes on 8087 and 80287 opcode generation: ! 757: * The 8086 does not check the coprocessor BUSY line when it encounters ! 758: * a coprocessor escape (an 8087 opcode). ! 759: * Therefore, an FWAIT must precede every 8087 opcode. ! 760: * Sequences which require coprocessor synchronization ! 761: * (e.g., awaiting completion of store from 8087 to 8086 memory) ! 762: * can include explicit FWAITs which do not precede 8087 ops. ! 763: * The 80286 checks its coprocessor BUSY line when it sees an 80287 opcode. ! 764: * Therefore, the 80287 does not require an FWAIT before each 80287 opcode, ! 765: * but explicit FWAITs are still required for synchronization. ! 766: * ! 767: * If EMUFIXUPS is true when the compiler is built, ! 768: * the OMF output writer targets the FWAIT which precedes an 8087 opcode ! 769: * with a magic "M:..." fixup; ! 770: * this happens only in the OMF output writer n1/i8086/outomf.c. ! 771: * The linker can then create objects which use either 8087 hardware ! 772: * or software floating point emulation. In the latter case, the ! 773: * linker changes the 8087 instructions into traps to the emulator. ! 774: * ! 775: * If the compile-time variant VEMU87 is set, ! 776: * the compiler writes "call emu87" before each 8087 opcode ! 777: * and suppresses the leading FWAIT. ! 778: * The emulator "emu87" can execute "fwait; ret" or replace "call emu87" with ! 779: * "nop; nop; fwait" if an 8087 is actually present at runtime. ! 780: */ ! 781: ! 782: /* ! 783: * Output an explicit FWAIT opcode for the 8087. ! 784: * The byte will be fiddled by an M:_WT fixup #if EMUFIXUPS. ! 785: */ ! 786: asmfwait() ! 787: { ! 788: hasfloat = 1; ! 789: if (isvariant(VEMU87)) { ! 790: asmemucall(); /* call emu87 */ ! 791: return; /* and suppress the FWAIT */ ! 792: } ! 793: if (pass != 0) { ! 794: berr(); ! 795: outfb(WAIT); ! 796: } ! 797: ++pc; ! 798: } ! 799: ! 800: /* ! 801: * Output an 8087 opcode for the 8087. ! 802: * The "prefix" argument is just the A_PREFX code from the address. ! 803: * The opcode will be preceded by an FWAIT if necessary, ! 804: * and the FWAIT will be fiddled by an M:_W?S fixup #if EMUFIXUPS. ! 805: */ ! 806: asmfop(op, prefix) ! 807: { ! 808: hasfloat = 1; ! 809: if (isvariant(VEMU87)) { ! 810: asmemucall(); /* call emu87 */ ! 811: if (pass != 0) ! 812: outfb(op); /* and suppress FWAIT */ ! 813: pc++; ! 814: return; ! 815: } ! 816: #if !EMUFIXUPS ! 817: if (isvariant(V80287)) { ! 818: if (pass != 0) { ! 819: berr(); ! 820: outfb(op); /* also suppress FWAIT for 80287 */ ! 821: } ! 822: pc++; ! 823: return; ! 824: } ! 825: #endif ! 826: if (pass != 0) { ! 827: berr(); ! 828: outfw(op<<8|WAIT, prefix); ! 829: } ! 830: pc += 2; ! 831: } ! 832: ! 833: /* ! 834: * Assemble a call to the IEEE software floating point 8087 emulator. ! 835: */ ! 836: asmemucall(){ ! 837: if (pass != 0) { ! 838: berr(); ! 839: outemucall(); ! 840: } ! 841: pc += (isvariant(VSMALL)) ? 3 : 5; ! 842: } ! 843: ! 844: /* ! 845: * Output a call to the 8087 emulator. ! 846: * Called from above and from genepilog (for FWAIT in epilog). ! 847: */ ! 848: outemucall(){ ! 849: static SYM *emu87p; ! 850: ! 851: if (emu87p == NULL) ! 852: emu87p = glookup("emu87", 0); ! 853: if (isvariant(VSMALL)) { /* SMALL model */ ! 854: outab(0xE8); /* near call */ ! 855: outxw(emu87p, 0, 1); /* emu87, pc-relative */ ! 856: } else { /* LARGE model */ ! 857: outab(0x9A); /* far call */ ! 858: outxw(emu87p, 0, 0); /* offset, absolute */ ! 859: outsb(emu87p); /* segment */ ! 860: } ! 861: } ! 862: ! 863: aerr(ip1) ! 864: register INS *ip1; ! 865: { ! 866: register SYM *sp; ! 867: register int i; ! 868: ! 869: printf("aerr: op=%d\n", ip1->i_op); ! 870: for (i=0; i<ip1->i_naddr; ++i) { ! 871: printf("Operand %d:", i); ! 872: printf(" mode=%04x", ip1->i_af[i].a_mode); ! 873: printf(" offs=%d", ip1->i_af[i].a_value); ! 874: if ((sp=ip1->i_af[i].a_sp) != NULL) { ! 875: if ((sp->s_flag&S_LABNO) != 0) ! 876: printf(" off L%d", sp->s_labno); ! 877: else ! 878: printf(" off %s", sp->s_id); ! 879: } ! 880: printf("\n"); ! 881: } ! 882: cbotch("aerr"); ! 883: } ! 884: ! 885: berr() ! 886: { ! 887: if (pcseg == SBSS) ! 888: cbotch("bss"); ! 889: } ! 890: ! 891: isalax(afp) ! 892: register AFIELD *afp; ! 893: { ! 894: if (afp->a_mode==A_RAX || afp->a_mode==A_RAL) ! 895: return (1); ! 896: return (0); ! 897: } ! 898: ! 899: /* ! 900: * This routine checks if the argument AFIELD is a valid short word immediate, ! 901: * as used by the special s:w encoding on some instructions. ! 902: * True return if so. ! 903: * The legality of the mode and the fact that ! 904: * the AFIELD is an immediate have already been checked. ! 905: */ ! 906: isshort(afp) ! 907: register AFIELD *afp; ! 908: { ! 909: register ADDRESS value; ! 910: ! 911: if (afp->a_sp == NULL) { ! 912: value = afp->a_value & 0xFF80; /* Top 9 */ ! 913: if (value==0xFF80 || value==0x0000) ! 914: return (1); ! 915: } ! 916: return (0); ! 917: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.