/* asmflt.c -- microsoft 80x86 assembler ** ** microsoft (r) macro assembler ** copyright (c) microsoft corp 1986. all rights reserved ** ** randy nevin ** ** 10/90 - Quick conversion to 32 bit by Jeff Spencer */ #include #include "asm86.h" #include "asmfcn.h" #include "asmctype.h" #include "asmopcod.h" #define TOLOWER(c) (c | 0x20) /* works only for alpha inputs */ /* Handle 8087 opcodes, they have the following types: Fnoargs: No arguments at all. F2memstk: 0-2 args; memory 4,8 byte | ST,ST(i) | ST(i),ST | blank( equiv ST ) Fstks: ST(i),ST Fmemstk: memory 4,8 | ST | ST(i) | blank Fstk: ST(i) Fmem42: memory 4,8 byte Fmem842: memory 2,4,8 bytes Fmem4810 memory 4,8,10 bytes | ST(i) Fmem2: memory 2 byte Fmem14: memory 14 bytes( don't force size ) Fmem94: memory 94 bytes( don't force size ) Fwait: Noargs, output WAIT Fbcdmem: memory Bcd */ /*** fltwait - output WAIT for 8087 instruction * * fltwait (p); * * Entry * Exit * Returns * Calls */ VOID PASCAL CODESIZE fltwait ( UCHAR fseg ){ register SHORT idx; char override; register struct psop *pso; if (fltemulate) { idx = 0; /* Check for data and fixup space */ if (pass2 && (emitcleanq ((UCHAR)(5)) || !fixroom (15))) emitdumpdata (0xA1); /* RN */ if (opctype != FWAIT) { override = 0; if (fltdsc) { pso = &(fltdsc->dsckind.opnd); if ((idx = pso->seg) < NOSEG && idx != fseg) override = 1; } if (override) emitfltfix ('I',fltfixmisc[idx][0],&fltfixmisc[idx][1]); else emitfltfix ('I','D',&fltfixmisc[7][1]); } else { emitfltfix ('I','W', &fltfixmisc[8][1]); emitopcode(0x90); } } if (fltemulate || cputype&P86 || (cpu & FORCEWAIT)) { emitopcode (O_WAIT); if (fltemulate && override && idx) emitfltfix ('J',fltfixmisc[idx+3][0],&fltfixmisc[idx+3][1]); } } SHORT CODESIZE if_fwait() { /* if second byte of opcode is 'N', we don't generate fwait */ return (TOLOWER(svname.pszName[1]) != 'n'); } /*** fltmodrm - emit 8087 MODRM byte * * fltmodrm (base, p); * * Entry * Exit * Returns * Calls * Note The MODRM byte for 8087 opcode: * M M b b b R / M * M = mode, 3 is for non-memory 8087 * b = base opcode. Together with ESC gives 6 bit opcode * R/M memory indexing type */ VOID PASCAL CODESIZE fltmodrm ( register USHORT base, struct fltrec *p ){ register USHORT mod; mod = modrm; if (!fltdsc) { if (mod < 8) mod <<= 3; if (mod < 0xC0) mod += 0xC0; /* ST(i) mode */ emitopcode ((UCHAR)(mod + base + p->stknum)); } else { emitmodrm ((USHORT)fltdsc->dsckind.opnd.mode, (USHORT)(mod + base), fltdsc->dsckind.opnd.rm); emitrest (fltdsc); } } /*** fltscan - scan operands and build fltdsc * * fltscan (p); * * Entry * Exit * Returns * Calls */ VOID PASCAL CODESIZE fltscan ( register struct fltrec *p ){ register struct psop *pso; p->args = FALSE; fltdsc = NULL; skipblanks (); if (ISTERM (PEEKC ())) { p->fseg = NOSEG; p->stknum = 1; } else { p->args = TRUE; p->fseg = DSSEG; fltdsc = expreval (&p->fseg); pso = &(fltdsc->dsckind.opnd); if (pso->mode == 3 && !(pso->rm == 0 && opcbase == O_FSTSW && modrm == R_FSTSW && (cputype & (P286|P386)))) errorc (E_IUR); /* Illegal use of reg */ if (1 << FLTSTACK & pso->dtype) { /* Have ST or ST(i) */ p->stknum = pso->doffset & 7; if (pso->doffset > 7 || pso->dsign) /* # too big */ errorc (E_VOR); if (pso->dsegment || pso->dcontext || pso->dflag == XTERNAL || pso->mode != 4) /* Must have a constant */ errorc (E_CXP); /* This means ST(i) */ pso->mode = 3; oblititem (fltdsc); fltdsc = NULL; } else if (pso->mode == 4){ /* pass1 error caused invalide mode assignment, map immdiate to direct, error on pass 2 */ if (pass2) errorc(E_NIM); pso->mode = 2; if (wordsize == 4) pso->mode = 7; } } } /*** fltopcode - process 8087 opcode * * routine (); * * Entry * Exit * Returns * Calls */ VOID PASCAL CODESIZE fltopcode () { struct fltrec a; USHORT i; register struct psop *pso; /* Save opcode name */ switchname (); a.stknum = 0; /* Scan 1st arg, if any */ fltscan (&a); if (if_fwait() || (opcbase == O_FNOP && modrm == R_FNOP)) fltwait (a.fseg); if (fltdsc){ pso = &(fltdsc->dsckind.opnd); emit67(pso, NULL); } switch (opctype) { case FNOARGS: /* No args allowed */ a.stknum = 0; if (opcbase == O_FSETPM && modrm == R_FSETPM) { if (!(cputype&PROT)) errorcSYN (); } /* Output escape byte */ emitopcode (opcbase); fltmodrm (0, &a); if (a.args) /* Operands not allowed */ errorc (E_ECL); break; case FWAIT: a.stknum = 0; if (a.args) /* Operands not allowed */ errorc (E_ECL); break; case FSTK: if (TOLOWER(svname.pszName[1]) == 'f' && !a.args) /* ffree w/o arg */ errorc(E_MOP); /* Output Escape */ emitopcode (opcbase); /* Modrm byte */ fltmodrm (0, &a); if (fltdsc) /*Must be ST(i) */ errorc (E_IOT); break; case FMEM42: case FMEM842: case FMEM2: case FMEM14: case FMEM94: case FBCDMEM: /* All use a memory operand. Some force size */ if (fltemulate && !if_fwait()) /* Can't emulate */ errorc (E_7OE); if (!fltdsc) /* must have arg */ errorc (E_IOT); else { emitescape (fltdsc, a.fseg); if (opctype == FMEM42) { /* Integer 2,4 byte */ forcesize (fltdsc); if (pso->dsize == 4) /* 4 byte */ emitopcode (opcbase); else { emitopcode ((UCHAR)(opcbase + 4)); if (pso->dsize != 2) errorc (E_IIS); } } else if (opctype == FMEM842) { /* Int 8,4,2 */ forcesize (fltdsc); if (pso->dsize == 2 || pso->dsize == 8) emitopcode ((UCHAR)(opcbase + 4)); else { emitopcode (opcbase); if (pso->dsize != 4) errorc (E_IIS); } } else if ((opctype == FMEM2) || (opctype == FBCDMEM)) { if (opctype == FMEM2) if (pso->dsize != 2 && pso->dsize) errorc (E_IIS); else { if (cputype & (P286|P386) && opcbase == O_FSTSW && modrm == R_FSTSW && pso->mode == 3 && pso->rm == 0) { opcbase = O_FSTSWAX; modrm = R_FSTSWAX; } } else if (pso->dsize != 10 && pso->dsize ) errorc (E_IIS); emitopcode (opcbase); } else emitopcode (opcbase); if ((pso->mode == 3 || pso->mode == 4) && (opcbase != O_FSTSWAX || modrm != R_FSTSWAX)) /* Only memory operands */ errorc (E_IOT); if (opctype == FMEM842 && pso->dsize == 8) if (TOLOWER(svname.pszName[2]) == 'l') fltmodrm (5, &a); else fltmodrm (4, &a); else fltmodrm (0, &a); } break; case FSTKS: if (!a.args) /* Operand required */ errorc (E_MOP); else if (fltdsc) /* Must be stack */ errorc (E_IOT); else { /* ESC */ emitopcode (opcbase); /* ST(i) */ fltmodrm (0, &a); if (PEEKC () != ',') error (E_EXP,"comma"); /* Must have 2 args */ /* Get 2nd operand */ SKIPC (); fltscan (&a); pso = NULL; if (!a.args || fltdsc) errorc (E_IOT); if (a.stknum) errorc (E_OCI); } break; case FMEM4810: /* Fwait */ if (TOLOWER(svname.pszName[1]) == 'l') /* FLD */ if (!fltdsc) {/* Have ST(i) */ if (!a.args) /* fld w/o arg */ errorc(E_MOP); emitopcode (opcbase); fltmodrm (0, &a); } else { /* Any segment override */ emitescape (fltdsc, a.fseg); if (pso->dsize == 10) { /* Have temp real */ emitopcode ((UCHAR)(opcbase + 2)); fltmodrm (5, &a); } else { /* Have normal real */ forcesize (fltdsc); if (pso->dsize == 8) emitopcode ((UCHAR)(opcbase + 4)); else { emitopcode (opcbase); if (pso->dsize != 4) errorc (E_IOT); } fltmodrm (0, &a); } } else if (!fltdsc) { /* Have ST(i) */ /* Have FSTP */ if (!a.args) errorc( E_IOT ); emitopcode ((UCHAR)(opcbase + 4)); fltmodrm (0, &a); } else { emitescape (fltdsc, a.fseg); /* Any segment override */ if (pso->dsize == 10) { /* Have temp real */ emitopcode( (UCHAR)(opcbase + 2) ); fltmodrm (4, &a); } else { /* Have normal real */ forcesize (fltdsc); if (pso->dsize == 8) emitopcode( (UCHAR)(opcbase + 4) ); else emitopcode (opcbase); fltmodrm (0, &a); } } break; case F2MEMSTK: if (!a.args) { /* Have ST(1),ST */ emitopcode( (UCHAR)(opcbase + 6) ); if ((i = modrm & 7) > 3) modrm = i^1; fltmodrm (0, &a); } else if (!fltdsc) {/* Have stacks */ if (a.stknum == 0) emitopcode (opcbase); else { /* Might need to reverse R bit */ if ((modrm & 7) > 3) /* Have FSUBx FDIVx */ modrm ^= 1; emitopcode( (UCHAR)(opcbase + 4) ); /* D bit is set */ } /* Save in case ST(i) */ a.stk1st = a.stknum; if (PEEKC () != ',') /* Must have , */ error (E_EXP,"comma"); /* Get 2nd operand */ SKIPC (); fltscan (&a); if (fltdsc) /* not stack */ errorc (E_IOT); if (a.args && a.stknum && a.stk1st) errorc (E_IOT); if (a.stk1st) a.stknum = a.stk1st; fltmodrm (0, &a); } else { /* Have real memory */ forcesize (fltdsc); emitescape (fltdsc, a.fseg); if (pso->dsize == 8) emitopcode( (UCHAR)(opcbase + 4) ); else { emitopcode (opcbase); if (pso->dsize != 4) errorc (E_IIS); } fltmodrm (0, &a); } break; case FMEMSTK: if (!fltdsc)/* Have ST(i) */ if (TOLOWER(svname.pszName[1]) == 's') { /* Special case */ if (!a.args) errorc( E_IOT ); emitopcode( (UCHAR)(opcbase + 4) ); } else emitopcode (opcbase); else { /* Have real memory */ emitescape (fltdsc, a.fseg); forcesize (fltdsc); if (pso->dsize == 8) emitopcode( (UCHAR)(opcbase + 4) ); else { emitopcode (opcbase); if (pso->dsize != 4) errorc (E_IOT); } } fltmodrm (0, &a); break; } if (fltdsc) oblititem (fltdsc); }