From a7aba15e8efffb1c5d3097656f1a93955a64f01f Mon Sep 17 00:00:00 2001 From: Robert de Bath Date: Sat, 27 Jul 2002 09:23:57 +0200 Subject: Import origs.tar.gz --- bin86-0.3/as/mops.c | 2840 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2840 insertions(+) create mode 100644 bin86-0.3/as/mops.c (limited to 'bin86-0.3/as/mops.c') diff --git a/bin86-0.3/as/mops.c b/bin86-0.3/as/mops.c new file mode 100644 index 0000000..be4e0f6 --- /dev/null +++ b/bin86-0.3/as/mops.c @@ -0,0 +1,2840 @@ +/* + * bin86/as/mops.c + * + * Copyright (C) 1992 Bruce Evans + */ + +/* mops.c - handle pseudo-ops */ + +#include "const.h" +#include "type.h" +#include "globvar.h" +#include "opcode.h" +#include "scan.h" +#undef EXTERN +#define EXTERN +#include "address.h" + +#define is8bitadr(offset) ((offset_t) offset < 0x100) +#define is8bitsignedoffset(offset) ((offset_t) (offset) + 0x80 < 0x100) +#define pass2 pass + +FORWARD void mshort2 P((void)); +FORWARD reg_pt regchk P((void)); +FORWARD void reldata P((void)); + +#ifdef I80386 + +#define iswordadr(offset) ((offset_t) (offset) < 0x10000L) +#define iswordoffset(offset) ((offset_t) (offset) + 0x8000L < 0x10000L) +#define iswordorswordoffset(offset) ((offset_t) (offset) + 0xFFFFL < 0x1FFFEL) + +#define BYTE_SEGWORD 0x00 +#define isspecreg(r) ((r) >= CR0REG && (r) <= TR7REG) + +#define BASE_MASK 0x07 +#define BASE_SHIFT 0 +#define INDEX_MASK 0x38 +#define INDEX_SHIFT 3 +#define MOD_MASK 0xC0 +# define REG_MOD 0xC0 +# define MEM0_MOD 0x00 +# define MEM1_MOD 0x40 +# define MEM2_MOD 0x80 +#define REG_MASK 0x38 +#define REG_SHIFT 3 +#define RM_MASK 0x07 +#define RM_SHIFT 0 +# define D16_RM 0x06 +# define D32_RM 0x05 +# define SIB_NOBASE 0x05 +# define SIB_RM 0x04 +#define SREG_MASK 0x38 +#define SREG_SHIFT 3 +#define SS_MASK 0xC0 +#define SS_SHIFT 6 + +#define SEGMOV 0x04 +#define SIGNBIT 0x02 +#define TOREGBIT 0x02 +#define WORDBIT 0x01 + +PRIVATE opcode_t baseind16[] = +{ + 0x00, /* BP + BP, illegal */ + 0x00, /* BX + BP, illegal */ + 0x03, /* DI + BP */ + 0x02, /* SI + BP */ + 0x00, /* BP + BX, illegal */ + 0x00, /* BX + BX, illegal */ + 0x01, /* DI + BX */ + 0x00, /* SI + BX */ + 0x03, /* BP + DI */ + 0x01, /* BX + DI */ + 0x00, /* DI + DI, illegal */ + 0x00, /* SI + DI, illegal */ + 0x02, /* BP + SI */ + 0x00, /* BX + SI */ + 0x00, /* DI + SI, illegal */ + 0x00, /* SI + SI, illegal */ +}; + +PRIVATE opcode_t regbits[] = +{ + 0x05 << REG_SHIFT, /* BP */ + 0x03 << REG_SHIFT, /* BX */ + 0x07 << REG_SHIFT, /* DI */ + 0x06 << REG_SHIFT, /* SI */ + + 0x00 << REG_SHIFT, /* EAX */ + 0x05 << REG_SHIFT, /* EBP */ + 0x03 << REG_SHIFT, /* EBX */ + 0x01 << REG_SHIFT, /* ECX */ + 0x07 << REG_SHIFT, /* EDI */ + 0x02 << REG_SHIFT, /* EDX */ + 0x06 << REG_SHIFT, /* ESI */ + 0x04 << REG_SHIFT, /* ESP */ + + 0x00 << REG_SHIFT, /* AX */ + 0x01 << REG_SHIFT, /* CX */ + 0x02 << REG_SHIFT, /* DX */ + 0x04 << REG_SHIFT, /* SP */ + + 0x04 << REG_SHIFT, /* AH */ + 0x00 << REG_SHIFT, /* AL */ + 0x07 << REG_SHIFT, /* BH */ + 0x03 << REG_SHIFT, /* BL */ + 0x05 << REG_SHIFT, /* CH */ + 0x01 << REG_SHIFT, /* CL */ + 0x06 << REG_SHIFT, /* DH */ + 0x02 << REG_SHIFT, /* DL */ + + 0x01 << REG_SHIFT, /* CS */ + 0x03 << REG_SHIFT, /* DS */ + 0x00 << REG_SHIFT, /* ES */ + 0x04 << REG_SHIFT, /* FS */ + 0x05 << REG_SHIFT, /* GS */ + 0x02 << REG_SHIFT, /* SS */ + + 0x00 << REG_SHIFT, /* CR0 */ + 0x02 << REG_SHIFT, /* CR2 */ + 0x03 << REG_SHIFT, /* CR3 */ + + 0x00 << REG_SHIFT, /* DR0 */ + 0x01 << REG_SHIFT, /* DR1 */ + 0x02 << REG_SHIFT, /* DR2 */ + 0x03 << REG_SHIFT, /* DR3 */ + 0x06 << REG_SHIFT, /* DR6 */ + 0x07 << REG_SHIFT, /* DR7 */ + + 0x03 << REG_SHIFT, /* TR3 */ + 0x04 << REG_SHIFT, /* TR4 */ + 0x05 << REG_SHIFT, /* TR5 */ + 0x06 << REG_SHIFT, /* TR6 */ + 0x07 << REG_SHIFT, /* TR7 */ + + 0x00 << REG_SHIFT, /* ST(0) */ + 0x01 << REG_SHIFT, /* ST(1) */ + 0x02 << REG_SHIFT, /* ST(2) */ + 0x03 << REG_SHIFT, /* ST(3) */ + 0x04 << REG_SHIFT, /* ST(4) */ + 0x05 << REG_SHIFT, /* ST(5) */ + 0x06 << REG_SHIFT, /* ST(6) */ + 0x07 << REG_SHIFT, /* ST(7) */ +}; + +PRIVATE opsize_t regsize[] = +{ + 2, /* BP */ + 2, /* BX */ + 2, /* DI */ + 2, /* SI */ + + 4, /* EAX */ + 4, /* EBP */ + 4, /* EBX */ + 4, /* ECX */ + 4, /* EDI */ + 4, /* EDX */ + 4, /* ESI */ + 4, /* ESP */ + + 2, /* AX */ + 2, /* CX */ + 2, /* DX */ + 2, /* SP */ + + 1, /* AH */ + 1, /* AL */ + 1, /* BH */ + 1, /* BL */ + 1, /* CH */ + 1, /* CL */ + 1, /* DH */ + 1, /* DL */ + + 2, /* CS */ + 2, /* DS */ + 2, /* ES */ + 2, /* FS */ + 2, /* GS */ + 2, /* SS */ + + 4, /* CR0 */ + 4, /* CR2 */ + 4, /* CR3 */ + + 4, /* DR0 */ + 4, /* DR1 */ + 4, /* DR2 */ + 4, /* DR3 */ + 4, /* DR6 */ + 4, /* DR7 */ + + 4, /* TR3 */ + 4, /* TR4 */ + 4, /* TR5 */ + 4, /* TR6 */ + 4, /* TR7 */ + + 10, /* ST(0) */ + 10, /* ST(1) */ + 10, /* ST(2) */ + 10, /* ST(3) */ + 10, /* ST(4) */ + 10, /* ST(5) */ + 10, /* ST(6) */ + 10, /* ST(7) */ + + 0, /* NOREG */ +}; + +PRIVATE opcode_t regsegword[] = +{ + WORDBIT, /* BP */ + WORDBIT, /* BX */ + WORDBIT, /* DI */ + WORDBIT, /* SI */ + + WORDBIT, /* EAX */ + WORDBIT, /* EBP */ + WORDBIT, /* EBX */ + WORDBIT, /* ECX */ + WORDBIT, /* EDI */ + WORDBIT, /* EDX */ + WORDBIT, /* ESI */ + WORDBIT, /* ESP */ + + WORDBIT, /* AX */ + WORDBIT, /* CX */ + WORDBIT, /* DX */ + WORDBIT, /* SP */ + + BYTE_SEGWORD, /* AH */ + BYTE_SEGWORD, /* AL */ + BYTE_SEGWORD, /* BH */ + BYTE_SEGWORD, /* BL */ + BYTE_SEGWORD, /* CH */ + BYTE_SEGWORD, /* CL */ + BYTE_SEGWORD, /* DH */ + BYTE_SEGWORD, /* DL */ + + SEGMOV, /* CS */ + SEGMOV, /* DS */ + SEGMOV, /* ES */ + SEGMOV, /* FS */ + SEGMOV, /* GS */ + SEGMOV, /* SS */ + + 0x20, /* CR0 */ + 0x20, /* CR2 */ + 0x20, /* CR3 */ + + 0x21, /* DR0 */ + 0x21, /* DR1 */ + 0x21, /* DR2 */ + 0x21, /* DR3 */ + 0x21, /* DR6 */ + 0x21, /* DR7 */ + + 0x24, /* TR3 */ + 0x24, /* TR4 */ + 0x24, /* TR5 */ + 0x24, /* TR6 */ + 0x24, /* TR7 */ + + 0x00, /* ST(0) */ + 0x00, /* ST(1) */ + 0x00, /* ST(2) */ + 0x00, /* ST(3) */ + 0x00, /* ST(4) */ + 0x00, /* ST(5) */ + 0x00, /* ST(6) */ + 0x00, /* ST(7) */ + + 0x00, /* NOREG */ +}; + +PRIVATE opcode_t rm[] = +{ + 0x05, /* BP */ + 0x03, /* BX */ + 0x07, /* DI */ + 0x06, /* SI */ + + 0x00, /* EAX */ + 0x05, /* EBP */ + 0x03, /* EBX */ + 0x01, /* ECX */ + 0x07, /* EDI */ + 0x02, /* EDX */ + 0x06, /* ESI */ + 0x04, /* ESP */ + + 0x00, /* AX */ + 0x01, /* CX */ + 0x02, /* DX */ + 0x04, /* SP */ + + 0x04, /* AH */ + 0x00, /* AL */ + 0x07, /* BH */ + 0x03, /* BL */ + 0x05, /* CH */ + 0x01, /* CL */ + 0x06, /* DH */ + 0x02, /* DL */ + + 0x01, /* CS */ + 0x03, /* DS */ + 0x00, /* ES */ + 0x04, /* FS */ + 0x05, /* GS */ + 0x02, /* SS */ + + 0x00, /* CR0 */ + 0x00, /* CR2 */ + 0x00, /* CR3 */ + + 0x00, /* DR0 */ + 0x00, /* DR1 */ + 0x00, /* DR2 */ + 0x00, /* DR3 */ + 0x00, /* DR6 */ + 0x00, /* DR7 */ + + 0x00, /* TR3 */ + 0x00, /* TR4 */ + 0x00, /* TR5 */ + 0x00, /* TR6 */ + 0x00, /* TR7 */ + + 0x00, /* ST(0) */ + 0x00, /* ST(1) */ + 0x00, /* ST(2) */ + 0x00, /* ST(3) */ + 0x00, /* ST(4) */ + 0x00, /* ST(5) */ + 0x00, /* ST(6) */ + 0x00, /* ST(7) */ + + 0x04, /* null index reg for sib only */ +}; + +PRIVATE opcode_t rmfunny[] = +{ + 0x06, /* BP */ + 0x07, /* BX */ + 0x05, /* DI */ + 0x04, /* SI */ +}; + +PRIVATE opcode_t segoverride[] = +{ + 0x2E, /* CS */ + 0x3E, /* DS */ + 0x26, /* ES */ + 0x64, /* FS */ + 0x65, /* GS */ + 0x36, /* SS */ +}; + +PRIVATE opcode_t ss[] = /* scale to ss bits */ +{ + 0x00, /* x0, illegal */ + 0x00 << SS_SHIFT, /* x1 */ + 0x01 << SS_SHIFT, /* x2 */ + 0x00, /* x3, illegal */ + 0x02 << SS_SHIFT, /* x4 */ + 0x00, /* x5, illegal */ + 0x00, /* x6, illegal */ + 0x00, /* x7, illegal */ + 0x03 << SS_SHIFT, /* x8 */ +}; + +PRIVATE unsigned char calljmp_kludge; +PRIVATE opcode_t direction; +PRIVATE bool_t fpreg_allowed; +PRIVATE opcode_t segword; +/* + Values of segword: + BYTE_SEGWORD for byte ea's. + SEGMOV for segment registers + opcode for special registers + WORDBIT for other word and dword ea's +*/ + +PRIVATE struct ea_s source; +PRIVATE struct ea_s source2; +PRIVATE struct ea_s target; + +FORWARD void Eb P((struct ea_s *eap)); +FORWARD void Ew P((struct ea_s *eap)); +FORWARD void Ev P((struct ea_s *eap)); +FORWARD void Ex P((struct ea_s *eap)); +FORWARD void Gw P((struct ea_s *eap)); +FORWARD void Gv P((struct ea_s *eap)); +FORWARD void Gx P((struct ea_s *eap)); +FORWARD void buildea P((struct ea_s *eap)); +FORWARD void buildfloat P((void)); +FORWARD void buildfreg P((void)); +FORWARD void buildimm P((struct ea_s *eap, bool_pt signflag)); +FORWARD void buildregular P((void)); +FORWARD void buildsegword P((struct ea_s *eap)); +FORWARD void buildunary P((opcode_pt opc)); +FORWARD opsize_pt displsize P((struct ea_s *eap)); +FORWARD reg_pt fpregchk P((void)); +FORWARD bool_pt getaccumreg P((struct ea_s *eap)); +FORWARD void getbinary P((void)); +FORWARD bool_pt getdxreg P((struct ea_s *eap)); +FORWARD void getea P((struct ea_s *eap)); +FORWARD void getimmed P((struct ea_s *eap, count_t immcount)); +FORWARD void getindirect P((struct ea_s *eap)); +FORWARD void getshift P((struct ea_s *eap)); +FORWARD reg_pt indregchk P((reg_pt matchreg)); +FORWARD void kgerror P((error_pt errnum)); +FORWARD void lbranch P((unsigned backamount)); +FORWARD void notbytesize P((struct ea_s *eap)); +FORWARD void notimmed P((struct ea_s *eap)); +FORWARD void notindirect P((struct ea_s *eap)); +FORWARD void notsegorspecreg P((struct ea_s *eap)); +FORWARD void yesimmed P((struct ea_s *eap)); +FORWARD void yes_samesize P((void)); + +PRIVATE void Eb(eap) +register struct ea_s *eap; +{ + Ex(eap); + if (eap->size != 0x1) + { +#ifndef NODEFAULTSIZE + if (eap->size == 0x0) + eap->size = 0x1; + else +#endif + kgerror(ILL_SIZE); + } +} + +PRIVATE void Ew(eap) +register struct ea_s *eap; +{ + Ex(eap); + if (eap->size != 0x2) + { +#ifndef NODEFAULTSIZE + if (eap->size == 0x0) + eap->size = 0x2; + else +#endif + kgerror(ILL_SIZE); + } +} + +PRIVATE void Ev(eap) +register struct ea_s *eap; +{ + Ex(eap); + notbytesize(eap); +} + +PRIVATE void Ex(eap) +register struct ea_s *eap; +{ + getea(eap); + notimmed(eap); + notsegorspecreg(eap); +} + +PRIVATE void Gd(eap) +register struct ea_s *eap; +{ + Gx(eap); + if (eap->size != 0x4) + kgerror(ILL_SIZE); +} + +PRIVATE void Gw(eap) +register struct ea_s *eap; +{ + Gx(eap); + if (eap->size != 0x2) + kgerror(ILL_SIZE); +} + +PRIVATE void Gv(eap) +register struct ea_s *eap; +{ + Gx(eap); + notbytesize(eap); +} + +PRIVATE void Gx(eap) +register struct ea_s *eap; +{ + Ex(eap); + notindirect(eap); +} + +PRIVATE void buildea(eap) +register struct ea_s *eap; +{ + opsize_t asize; + + ++mcount; + lastexp = eap->displ; + if (eap->indcount == 0x0) + postb = REG_MOD | rm[eap->base]; + else + { + if (eap->base == NOREG) + { + if (eap->index == NOREG) + { + if ((asize = displsize(eap)) > 0x2) + postb = D32_RM; + else + postb = D16_RM; + } + else + { + asize = 0x4; + postb = SIB_NOBASE; /* for sib later */ + } + } + else + { + if (eap->base > MAX16BITINDREG) + { + asize = 0x4; + postb = rm[eap->base]; + } + else + { + asize = 0x2; + if (!(lastexp.data & UNDBIT) && + !iswordorswordoffset(lastexp.offset)) + error(ABOUNDS); + if (eap->index == NOREG) + postb = rmfunny[eap->base]; + else if (eap->base <= MAX16BITINDREG) + postb = baseind16[eap->base + 0x4 * eap->index]; + } + } + if (asize != defsize) + aprefix = 0x67; + if (eap->base == NOREG) + mcount += asize; + else if (lastexp.data & (FORBIT | RELBIT | UNDBIT) || + !is8bitsignedoffset(lastexp.offset)) + { + postb |= MEM2_MOD; + mcount += asize; + } + else if (lastexp.offset != 0x0 || + eap->base == BPREG && eap->index == NOREG || + eap->base == EBPREG) + { + postb |= MEM1_MOD; + ++mcount; + } + if (asize > 0x2 && (eap->base == ESPREG || eap->index != NOREG)) + { + sib = ss[eap->scale] | + (rm[eap->index] << INDEX_SHIFT) | + (postb & RM_MASK); + postb = (postb & MOD_MASK) | SIB_RM; + ++mcount; + } + } +} + +PRIVATE void buildfloat() +{ + if (mcount != 0x0) + { + buildea(&source); + oprefix = 0x0; + postb |= (opcode & 0x07) << REG_SHIFT; + opcode = ESCAPE_OPCODE_BASE | ((opcode & 0x70) >> 0x4); + } +} + +PRIVATE void buildfreg() +{ + mcount += 0x2; + oprefix = 0x0; + postb = REG_MOD | ((opcode & 0x07) << REG_SHIFT) | (target.base - ST0REG); + opcode = ESCAPE_OPCODE_BASE | ((opcode & 0x70) >> 0x4); +} + +PRIVATE void buildimm(eap, signflag) +register struct ea_s *eap; +bool_pt signflag; +{ + immadr = eap->displ; + immcount = eap->size; + if (!(immadr.data & (FORBIT | RELBIT | UNDBIT))) + { + if (immcount == 0x1) + { + if ((offset_t) (immadr.offset + 0x80) >= 0x180) + datatoobig(); + } + else if (signflag && is8bitsignedoffset(immadr.offset)) + { + opcode |= SIGNBIT; + immcount = 0x1; + } + else if (immcount == 0x2) + { + if ((offset_t) (immadr.offset + 0x8000L) >= 0x18000L) + datatoobig(); + } + } +} + +PRIVATE void buildregular() +{ + if (mcount != 0x0) + { + buildea(&target); + postb |= regbits[source.base]; + } +} + +/* Check size and build segword. */ + +PRIVATE void buildsegword(eap) +register struct ea_s *eap; +{ + if (eap->size == 0x0) +#ifdef NODEFAULTSIZE + kgerror(SIZE_UNK); +#else + eap->size = defsize; +#endif + if (eap->indcount != 0x0 || eap->base == NOREG) + { + segword = WORDBIT; + if (eap->size == 0x1) + segword = BYTE_SEGWORD; + } + else + segword = regsegword[eap->base]; +} + +PRIVATE void buildunary(opc) +opcode_pt opc; +{ + if (mcount != 0x0) + { + buildea(&target); + postb |= opcode; + opcode = opc; + } +} + +PRIVATE opsize_pt displsize(eap) +register struct ea_s *eap; +{ + opsize_t asize; + + asize = defsize; + if (!(eap->displ.data & UNDBIT)) + { + if (asize > 0x2) + { + if (!(eap->displ.data & (FORBIT | RELBIT)) && + iswordadr(eap->displ.offset)) + asize = 0x2; + } + else if (!iswordorswordoffset(eap->displ.offset)) + /* should really use iswordadr() */ + /* but compiler generates signed offsets */ + { + if (!(eap->displ.data & (FORBIT | RELBIT))) + asize = 0x4; + else if (pass2) + error(ABOUNDS); + } + } + return asize; +} + +PRIVATE reg_pt fpregchk() +{ + reg_pt fpreg; + + fpreg_allowed = TRUE; + fpreg = regchk(); + fpreg_allowed = FALSE; + if (fpreg != ST0REG) + return NOREG; + getsym(); + if (sym == LPAREN) + { + getsym(); + if (sym != INTCONST || (unsigned) number >= 0x8) + error(ILL_FP_REG); + else + { + fpreg += number; + getsym(); + if (sym != RPAREN) + error(RPEXP); + else + getsym(); + } + } + return fpreg; +} + +PRIVATE bool_pt getaccumreg(eap) +register struct ea_s *eap; +{ + if ((eap->base = regchk()) != AXREG && eap->base != ALREG + && eap->base != EAXREG) + return FALSE; + getsym(); + if ((eap->size = regsize[eap->base]) > 0x1 && eap->size != defsize) + oprefix = 0x66; + return TRUE; +} + +/* + Get binary ea's in target & source (flipped if direction is set). + Put size in source if not already. + Initialise direction, segword, bump mcount. +*/ + +PRIVATE void getbinary() +{ + ++mcount; + getea(&target); + if (target.indcount == 0x0 && target.base == NOREG) + { + error(ILL_IMM_MODE); + target.base = AXREG; + target.size = defsize; + } + getcomma(); + getea(&source); + if (source.size == 0x0) + source.size = target.size; + else if (target.size != 0x0 && target.size != source.size) + { + kgerror(MISMATCHED_SIZE); + return; + } + if (source.indcount == 0x0 && regsegword[target.base] < SEGMOV) + direction = 0x0; + else if (target.indcount == 0x0 && regsegword[source.base] < SEGMOV) + { + struct ea_s swap; + + direction = TOREGBIT; + swap = source; + source = target; + target = swap; + } + else if (target.indcount != 0x0) + { + kgerror(ILL_IND_TO_IND); + return; + } + else + { + kgerror(ILL_SEG_REG); + return; + } + buildsegword(&source); +} + +PRIVATE bool_pt getdxreg(eap) +register struct ea_s *eap; +{ + if ((eap->base = regchk()) != DXREG) + return FALSE; + getsym(); + return TRUE; +} + +/* parse effective address */ + +/* + Syntax is restrictive in that displacements must be in the right spots + and will not be added up. + + optional size-type prefix, which is + BYTE + BYTE PTR + WORD + WORD PTR + DWORD + DWORD PTR + PTR + reg + segreg + [scaled index] + where scaled index = + indreg + indreg*scale + indreg+indreg + indreg+indreg*scale + [scaled index+displ] + [scaled index-displ] + optional-immediate-prefix displ[scaled index] + [displ] + optional-imediate-prefix displ + (scaled index) -- anachronism + optional-imediate-prefix displ(scaled index) -- anachronism +*/ + +PRIVATE void getea(eap) +register struct ea_s *eap; +{ + bool_t leading_displ; + bool_t leading_immed; + register struct sym_s *symptr; + + leading_immed = leading_displ = lastexp.data = eap->indcount + = lastexp.offset = 0x0; + eap->index = eap->base = NOREG; + eap->scale = 0x1; + eap->size = mnsize; /* 0x1 for byte ops, else 0x0 */ + + if (sym == IDENT) + { + if ((symptr = gsymptr)->type & MNREGBIT) + { + if (symptr->data & SIZEBIT) + { + getsym(); + if (symptr->value_reg_or_op.op.opcode == 0x0) + eap->indcount = 0x2 - calljmp_kludge; + else + { + if (eap->size != 0x0) + { + if (eap->size != symptr->value_reg_or_op.op.opcode) + error(MISMATCHED_SIZE); + } + else + eap->size = symptr->value_reg_or_op.op.opcode; + if (eap->size > 0x1 && eap->size != defsize) + oprefix = 0x66; + if (sym == IDENT && + (symptr = gsymptr)->type & MNREGBIT && + symptr->data & SIZEBIT && + symptr->value_reg_or_op.op.routine == PTROP) + { + getsym(); + eap->indcount = 0x2 - calljmp_kludge; + } + } + } + } + if (!(symptr->type & (LABIT | MACBIT | MNREGBIT | VARBIT))) + symptr->data |= FORBIT; /* show seen in advance */ + } + if ((eap->base = regchk()) != NOREG) + { + getsym(); + if (eap->indcount != 0x0) + { + error(ILL_IND_PTR); + eap->indcount = 0x0; + } + if (eap->size != 0x0 && eap->size != regsize[eap->base]) + error(MISMATCHED_SIZE); + if ((eap->size = regsize[eap->base]) > 0x1 && eap->size != defsize) + oprefix = 0x66; + eap->displ = lastexp; + return; + } + if (sym != lindirect) + { + if (sym == IMMEDIATE || sym == STAR) + { + /* context-sensitive, STAR means signed immediate here */ + leading_immed = TRUE; + getsym(); + } + leading_displ = TRUE; + expres(); + eap->displ = lastexp; + } + if (sym == lindirect) + { + getsym(); + eap->indcount = 0x2 - calljmp_kludge; + if ((eap->base = indregchk(NOREG)) != NOREG) + { + if (eap->indcount == 0x0 && leading_displ) + error(IND_REQ); + getsym(); + if (sym == ADDOP) + { + getsym(); + if ((eap->index = indregchk(eap->base)) != NOREG) + getsym(); + else + { + if (eap->indcount == 0x0) + error(IND_REQ); + if (leading_displ) + error(REPEATED_DISPL); + expres(); /* this eats ADDOP, SUBOP, MULOP */ + } + } + if (sym == STAR) + { + /* context-sensitive, STAR means scaled here*/ + if (eap->index == NOREG && eap->base == ESPREG) + { + error(INDEX_REG_EXP); + eap->base = EAXREG; + } + getsym(); + factor(); + chkabs(); + if (!(lastexp.data & UNDBIT) && lastexp.offset != 0x1) + { + if (eap->base <= MAX16BITINDREG || + lastexp.offset != 0x2 && lastexp.offset != 0x4 && + lastexp.offset != 0x8) + error(ILL_SCALE); + else + { + eap->scale = lastexp.offset; + if (eap->index == NOREG) + { + eap->index = eap->base; + eap->base = NOREG; + } + } + } + lastexp.data = lastexp.offset = 0x0; + } + if ((sym == ADDOP || sym == SUBOP)) + { + if (eap->indcount == 0x0) + error(IND_REQ); + if (leading_displ) + error(REPEATED_DISPL); + expres(); + } + } + else + { + if (leading_displ) + error(REPEATED_DISPL); + expres(); + } + if (sym != rindirect) + error(rindexp); + else + getsym(); + } + else if (!leading_immed && idefsize <= 0x2) + eap->indcount = 0x1; /* compatibility kludge */ + if (!leading_displ) + eap->displ = lastexp; +} + +PRIVATE void getimmed(eap, immcount) +struct ea_s *eap; +count_t immcount; +{ + getea(eap); + yesimmed(eap); + if (mcount != 0x0) + { + eap->size = immcount; + buildimm(eap, FALSE); + } +} + +PRIVATE void getindirect(eap) +register struct ea_s *eap; +{ + getea(eap); + if (eap->indcount == 0x0) + kgerror(IND_REQ); +} + +PRIVATE void getshift(eap) +register struct ea_s *eap; +{ + getcomma(); + getea(eap); + if (eap->base != CLREG) + yesimmed(eap); +} + +/* + Check if current symbol is a compatible index register. + Generate error if it is a reg but not a compatible index. + Return register number (adjusted if necessary to a legal index) or NOREG. +*/ + +PRIVATE reg_pt indregchk(matchreg) +reg_pt matchreg; +{ + reg_pt reg; + + if ((reg = regchk()) != NOREG) + { + switch (matchreg) + { + case BPREG: + case BXREG: + if (reg != DIREG && reg != SIREG) + { + reg = SIREG; + error(INDEX_REG_EXP); + } + break; + case DIREG: + case SIREG: + if (reg != BPREG && reg != BXREG) + { + reg = BXREG; + error(INDEX_REG_EXP); + } + break; + case NOREG: + break; + default: + if (reg <= MAX16BITINDREG || reg == ESPREG) + { + reg = EAXREG; + error(INDEX_REG_EXP); + } + break; + } + if (reg > MAXINDREG && calljmp_kludge == 0x0) + { + if (matchreg != NOREG) + reg = EAXREG; + else + reg = BXREG; + error(INDEX_REG_EXP); + } + } + return reg; +} + +PRIVATE void kgerror(errnum) +error_pt errnum; +{ + error(errnum); + sprefix = oprefix = aprefix = mcount = 0x0; +} + +PRIVATE void lbranch(backamount) +unsigned backamount; +{ + mcount += defsize + 0x1; + if (pass2) + { + reldata(); + if (!(lastexp.data & (RELBIT | UNDBIT))) + { + lastexp.offset = lastexp.offset - lc - lcjump; + if (backamount != 0x0 && !(lastexp.data & IMPBIT) && + lastexp.offset + backamount < 0x80 + backamount) + error(SHORTB); /* -0x8? to 0x7F, warning */ + } + } +} + +/* BCC (long branches emulated by short branch over & long jump) */ + +PUBLIC void mbcc() +{ + getea(&target); + if (target.indcount >= 0x2 || target.base != NOREG) + kgerror(REL_REQ); + else + { + if (defsize != 0x2) + { + page = PAGE1_OPCODE; + ++mcount; + opcode += 0x10; + lbranch(0x84); + } + else + { + aprefix = opcode ^ 0x1; /* kludged storage for short branch + over */ + oprefix = defsize + 0x1; + mcount += 0x2; + opcode = JMP_OPCODE; + lbranch(0x83); + mcount -= 0x2; + } + } +} + +/* bswap r32 */ + +PUBLIC void mbswap() +{ + ++mcount; + Gd(&target); + opcode |= rm[target.base]; +} + +/* BR, CALL, J, JMP */ + +PUBLIC void mcall() +{ + opcode_pt far; + bool_t indirect; + register struct sym_s *symptr; + + far = 0x0; + if (sym == IDENT && (symptr = gsymptr)->type & MNREGBIT && + symptr->data & SIZEBIT && + symptr->value_reg_or_op.op.routine == FAROP) + { + far = 0x8; + getsym(); + } + indirect = FALSE; + if (asld_compatible && idefsize <= 0x2) + { + calljmp_kludge = 0x2; + if (sym == INDIRECT) + { + calljmp_kludge = 0x0; + indirect = TRUE; + getsym(); + } + } + getea(&target); + if (indirect && target.indcount == 0x1) + target.indcount = 0x2; + calljmp_kludge = 0x0; + if (sym == COLON) + { + if (opcode == JMP_SHORT_OPCODE) + opcode = JMP_OPCODE; + ++mcount; + yesimmed(&target); + getsym(); + getea(&source); + yesimmed(&source); + if (mcount != 0x0) + { + if (opcode == JMP_OPCODE) + opcode = 0xEA; + else + opcode = 0x9A; + lastexp = source.displ; + if (!(lastexp.data & (FORBIT | RELBIT | UNDBIT)) && + defsize == 0x2 && + (offset_t) (lastexp.offset + 0x8000L) >= 0x18000L) + datatoobig(); + mcount += defsize; + target.size = 0x2; + buildimm(&target, FALSE); + } + } + else if (target.indcount >= 0x2 || target.base != NOREG) + { + ++mcount; + notsegorspecreg(&target); + if (target.indcount == 0) + notbytesize(&target); + if (mcount != 0x0) + { + if (opcode == JMP_SHORT_OPCODE) + opcode = JMP_OPCODE; + buildea(&target); + if (opcode == JMP_OPCODE) + opcode = 0x20; + else + opcode = 0x10; + postb |= opcode + far; + opcode = 0xFF; + } + } + else if (opcode == JMP_SHORT_OPCODE) + { + if (jumps_long) + { + opcode = JMP_OPCODE; + lbranch(0x83); + } + else + { + lastexp = target.displ; + if (lastexp.data & IMPBIT) + { + error(NONIMPREQ); + lastexp.data = FORBIT | UNDBIT; + } + mshort2(); + } + } + else + lbranch(opcode == JMP_OPCODE ? 0x83 : 0x0); +} + +/* CALLI, JMPI */ + +PUBLIC void mcalli() +{ + bool_t indirect; + + ++mcount; + indirect = FALSE; + if (sym == INDIRECT) + { + getsym(); + indirect = TRUE; + } + getea(&target); + if (target.indcount >= 0x2 || target.base != NOREG) + indirect = TRUE; + if (indirect) + { + buildea(&target); + if (opcode == 0xEA) + opcode = 0x28; + else + opcode = 0x18; + postb |= opcode; + opcode = 0xFF; + } + else + { + getcomma(); + getea(&source); + yesimmed(&source); + if (mcount != 0x0) + { + lastexp = target.displ; + if (!(lastexp.data & (FORBIT | RELBIT | UNDBIT)) && + defsize == 0x2 && + (offset_t) (lastexp.offset + 0x8000L) >= 0x18000L) + datatoobig(); + mcount += defsize; + source.size = 0x2; + buildimm(&source, FALSE); + } + } +} + +/* DIV, IDIV, MUL */ + +PUBLIC void mdivmul() +{ + if (getaccumreg(&source)) + { + ++mcount; + getcomma(); + Ex(&target); + yes_samesize(); + buildunary(0xF6 | regsegword[source.base]); + } + else + mnegnot(); +} + +/* ENTER */ + +PUBLIC void menter() +{ + ++mcount; + getimmed(&target, 0x2); + getcomma(); + getimmed(&source, 0x1); + if (mcount != 0x0) + { + mcount += 2; + lastexp = target.displ; /* getimmed(&source) wiped it out */ + } +} + +/* arpl r/m16,r16 (Intel manual opcode chart wrongly says EwRw) */ + +PUBLIC void mEwGw() +{ + ++mcount; + Ew(&target); + getcomma(); + Gw(&source); + oprefix = 0x0; + buildregular(); +} + +/* [cmpxchg xadd] [r/m8,r8 r/m16,r16, r/m32,r32] */ + +PUBLIC void mExGx() +{ + ++mcount; + Ex(&target); + getcomma(); + Gx(&source); + yes_samesize(); + opcode |= segword; + buildregular(); +} + +PUBLIC void mf_inher() +{ + mcount += 0x2; + postb = REG_MOD | (opcode & ~REG_MOD); + opcode = ESCAPE_OPCODE_BASE | (opcode >> 0x6); + if (opcode == ESCAPE_OPCODE_BASE) + opcode = ESCAPE_OPCODE_BASE | 0x6; /* fix up encoding of fcompp */ +} + +/* [fldenv fnsave fnstenv frstor] mem */ + +PUBLIC void mf_m() +{ + ++mcount; + getindirect(&source); + if (source.size != 0x0) + kgerror(ILL_SIZE); + buildfloat(); +} + +/* [fldcw fnstcw] mem2i */ + +PUBLIC void mf_m2() +{ + ++mcount; + getindirect(&source); + if (source.size != 0x0 && source.size != 0x2) + kgerror(ILL_SIZE); + buildfloat(); +} + +/* fnstsw [mem2i ax] */ + +PUBLIC void mf_m2_ax() +{ + if (getaccumreg(&target)) + { + if (target.base != AXREG) + kgerror(ILLREG); + else + { + opcode = 0x74; + target.base = ST0REG; /* fake, really ax */ + buildfreg(); + } + } + else + mf_m2(); +} + +/* [fiadd ficom ficomp fidiv fidivr fimul fist fisub fisubr] [mem2i mem4i] */ + +PUBLIC void mf_m2_m4() +{ + ++mcount; + getindirect(&source); + if (source.size == 0x0) + kgerror(SIZE_UNK); + else if (source.size == 0x2) + opcode |= 0x40; + else if (source.size != 0x4) + kgerror(ILL_SIZE); + buildfloat(); +} + +/* [fild fistp] [mem2i mem4i mem8i] */ + +PUBLIC void mf_m2_m4_m8() +{ + ++mcount; + getindirect(&source); + if (source.size == 0x0) + kgerror(SIZE_UNK); + else if (source.size == 0x2) + opcode |= 0x40; + else if (source.size == 0x8) + opcode |= 0x45; /* low bits 0 -> 5 and 3 -> 7 */ + else if (source.size != 0x4) + kgerror(ILL_SIZE); + buildfloat(); +} + +/* [fcom fcomp] [mem4r mem8r optional-st(i)] */ + +PUBLIC void mf_m4_m8_optst() +{ + if (sym == EOLSYM) + { + target.base = ST1REG; + buildfreg(); + } + else + mf_m4_m8_st(); +} + +/* [fadd fdiv fdivr fmul fsub fsubr] [mem4r mem8r st,st(i) st(i),st] */ + +PUBLIC void mf_m4_m8_stst() +{ + target.base = fpregchk(); + if (target.base != NOREG) + { + getcomma(); + source.base = fpregchk(); + if (source.base == NOREG) + { + error(FP_REG_REQ); + source.base = ST0REG; + } + if (target.base == ST0REG) + target.base = source.base; + else + { + if (source.base != ST0REG) + error(ILL_FP_REG_PAIR); + opcode |= 0x40; + if ((opcode & 0x07) >= 0x4) + opcode ^= 0x01; /* weird swap of fdiv/fdivr, fsub/fsubr */ + } + buildfreg(); + } + else + { + ++mcount; + getindirect(&source); + if (source.size == 0x0) + kgerror(SIZE_UNK); + else if (source.size == 0x8) + opcode |= 0x40; + else if (source.size != 0x4) + kgerror(ILL_SIZE); + buildfloat(); + } +} + +/* fst [mem4r mem8r st(i)] */ + +PUBLIC void mf_m4_m8_st() +{ + target.base = fpregchk(); + if (target.base != NOREG) + { + if (opcode == FST_ENCODED) + opcode |= 0x40; + buildfreg(); + } + else + { + ++mcount; + getindirect(&source); + if (source.size == 0x0) + kgerror(SIZE_UNK); + else if (source.size == 0x8) + opcode |= 0x40; + else if (source.size != 0x4) + kgerror(ILL_SIZE); + buildfloat(); + } +} + +/* [fld fstp] [mem4r mem8r mem10r st(i)] */ + +PUBLIC void mf_m4_m8_m10_st() +{ + target.base = fpregchk(); + if (target.base != NOREG) + { + if (opcode == FSTP_ENCODED) + opcode |= 0x40; + buildfreg(); + } + else + { + ++mcount; + getindirect(&source); + if (source.size == 0x0) + kgerror(SIZE_UNK); + else if (source.size == 0x8) + opcode |= 0x40; + else if (source.size == 0xA) + opcode |= 0x25; /* low bits 0 -> 5 and 3 -> 7 */ + else if (source.size != 0x4) + kgerror(ILL_SIZE); + buildfloat(); + } +} + +/* [fbld fbstp] mem10r */ + +PUBLIC void mf_m10() +{ + ++mcount; + getindirect(&source); + if (source.size != 0xA) + kgerror(ILL_SIZE); + buildfloat(); +} + +/* ffree st(i) */ + +PUBLIC void mf_st() +{ + target.base = fpregchk(); + if (target.base == NOREG) + kgerror(FP_REG_REQ); + buildfreg(); +} + +/* [fucom fucomp fxch] optional-st(i) */ + +PUBLIC void mf_optst() +{ + if (sym == EOLSYM) + { + target.base = ST1REG; + buildfreg(); + } + else + mf_st(); +} + +/* [faddp fdivp fdivrp fmulp fsubp fsubrp] st(i),st */ + +PUBLIC void mf_stst() +{ + target.base = fpregchk(); + if (target.base == NOREG) + { + kgerror(FP_REG_REQ); + return; + } + getcomma(); + source.base = fpregchk(); + if (source.base == NOREG) + { + kgerror(FP_REG_REQ); + return; + } + if (source.base != ST0REG) + { + kgerror(ILL_FP_REG); + return; + } + buildfreg(); +} + +PUBLIC void mf_w_inher() +{ + sprefix = WAIT_OPCODE; + mf_inher(); +} + +/* [fsave fstenv] mem */ + +PUBLIC void mf_w_m() +{ + sprefix = WAIT_OPCODE; + mf_m(); +} + +/* fstcw mem2i */ + +PUBLIC void mf_w_m2() +{ + sprefix = WAIT_OPCODE; + mf_m2(); +} + +/* fstsw [mem2i ax] */ + +PUBLIC void mf_w_m2_ax() +{ + sprefix = WAIT_OPCODE; + mf_m2_ax(); +} + +/* ADC, ADD, AND, CMP, OR, SBB, SUB, XOR */ + +PUBLIC void mgroup1() +{ + getbinary(); + notsegorspecreg(&source); + if (mcount != 0x0) + { + if (source.base == NOREG) + { + if (target.indcount == 0x0 && (target.base == ALREG || + target.base == AXREG || + target.base == EAXREG && + (source.displ.data & (FORBIT | RELBIT | UNDBIT) || + !is8bitsignedoffset(source.displ.offset)))) + { + opcode |= 0x04 | segword; + buildimm(&source, FALSE); + } + else + { + buildunary(0x80 | segword); + buildimm(&source, TRUE); + } + } + else + { + opcode |= direction | segword; + buildregular(); + } + } +} + +/* RCL, RCR, ROL, ROR, SAL, SAR, SHL, SHR */ + +PUBLIC void mgroup2() +{ + ++mcount; + Ex(&target); + buildsegword(&target); + getshift(&source); + if (mcount != 0x0) + { + buildunary(0xD0 | segword); + if (source.base == CLREG) + opcode |= 0x2; + else if (source.displ.offset != 0x1) + { + opcode -= 0x10; + source.size = 0x1; + buildimm(&source, FALSE); + } + } +} + +/* LLDT, LTR, SLDT, STR, VERR, VERW */ + +PUBLIC void mgroup6() +{ + ++mcount; + Ew(&target); + oprefix = 0x0; + buildunary(0x0); +} + +/* INVLPG, LGDT, LIDT, LMSW, SGDT, SIDT, SMSW */ + +PUBLIC void mgroup7() +{ + ++mcount; + if (opcode == 0x20 || opcode == 0x30) + { + Ew(&target); + oprefix = 0x0; + } + else + { + getindirect(&target); + oprefix = 0x0; + if (target.size != 0x0 && target.size != 0x6) + error(MISMATCHED_SIZE); /* XXX - size 6 wrong for INVLPG? */ + } + buildunary(0x1); +} + +/* BT, BTR, BTS, BTC */ + +PUBLIC void mgroup8() +{ + ++mcount; + Ev(&target); + getcomma(); + /* Gv or Ib */ + getea(&source); + notindirect(&source); + notsegorspecreg(&source); + if (mcount != 0x0) + { + if (source.base == NOREG) + { + buildunary(0xBA); + source.size = 0x1; + buildimm(&source, TRUE); + } + else + { + yes_samesize(); + opcode += 0x83; + buildregular(); + } + } +} + +/* BSF, BSR, LAR, LSL (Intel manual opcode chart wrongly says GvEw for L*) */ + +PUBLIC void mGvEv() +{ + ++mcount; + Gv(&source); + getcomma(); + Ev(&target); + yes_samesize(); + buildregular(); +} + +/* bound [r16,m16&16 r32,m32&32] */ + +PUBLIC void mGvMa() +{ + ++mcount; + Gv(&source); + getcomma(); + getindirect(&target); + yes_samesize(); + buildregular(); +} + +/* LDS, LES, LFS, LGS, LSS */ + +PUBLIC void mGvMp() +{ + ++mcount; + Gv(&source); + getcomma(); + getindirect(&target); + if (target.size != 0x0 && target.size != 0x2 + source.size) + error(MISMATCHED_SIZE); + buildregular(); +} + +/* IMUL */ + +PUBLIC void mimul() +{ + ++mcount; + Ex(&target); + if (sym != COMMA) + { + buildsegword(&target); + buildunary(0xF6 | segword); + return; + } + getcomma(); + notindirect(&target); + source = target; /* direction is swapped */ + getea(&target); + notsegorspecreg(&target); + yes_samesize(); + if (sym != COMMA && (target.indcount != 0x0 || target.base != NOREG)) + { + page = PAGE1_OPCODE; + ++mcount; + opcode = 0xAF; + buildregular(); + } + else + { + if (sym == COMMA) + { + getsym(); + getea(&source2); + yesimmed(&source2); + } + else + { + source2 = target; + target = source; + } + source2.size = target.size; + if (is8bitsignedoffset(source2.displ.offset)) + { + source2.size = 0x1; + opcode = 0x6B; + } + else + { + source2.size = target.size; + opcode = 0x69; + } + buildregular(); + if (mcount != 0x0) + buildimm(&source2, FALSE); + } +} + +/* IN */ + +PUBLIC void min() +{ + ++mcount; + if (opcode & WORDBIT) /* inw; ind not supported */ + mnsize = 0x2; + if (sym == EOLSYM && mnsize != 0x0) + target.size = mnsize; + else + { + if (getaccumreg(&target)) + { + if (mnsize != 0x0 && regsize[target.base] != mnsize) + error(MISMATCHED_SIZE); + getcomma(); + } + else + target.size = regsize[target.base = mnsize < 0x2 ? ALREG : AXREG]; + opcode |= regsegword[target.base]; + if (!getdxreg(&source)) + { + getimmed(&source, 0x1); + opcode -= 0x8; + } + } + if (target.size > 0x1 && target.size != defsize) + oprefix = 0x66; +} + +/* DEC, INC */ + +PUBLIC void mincdec() +{ + ++mcount; + Ex(&target); + buildsegword(&target); + if (target.indcount == 0x0 && segword == WORDBIT) + opcode |= 0x40 | rm[target.base]; + else + buildunary(0xFE | segword); +} + +/* CBW, CWD, CMPSW, INSW, IRET, LODSW, POPA, POPF, PUSHA, PUSHF */ +/* MOVSW, OUTSW, SCASW, STOSW */ + +PUBLIC void minher16() +{ + minher(); + if (defsize != 0x2) + oprefix = 0x66; +} + +/* CWDE, CDQ, CMPSD, INSD, IRETD, LODSD, POPAD, POPFD, PUSHAD, PUSHFD */ +/* MOVSD, OUTSD, SCASD, STOSD */ + +PUBLIC void minher32() +{ + minher(); + if (defsize != 0x4) + oprefix = 0x66; +} + +/* AAD, AAM */ + +PUBLIC void minhera() +{ + ++mcount; + if (sym == EOLSYM) + { + target.displ.offset = 0xA; + target.size = 0x1; + buildimm(&target, FALSE); + } + else + getimmed(&target, 0x1); +} + +/* INT */ + +PUBLIC void mint() +{ + ++mcount; + getimmed(&target, 0x1); + if (!(immadr.data & (FORBIT | RELBIT | UNDBIT)) && + (opcode_t) immadr.offset == 0x3) + { + immcount = 0x0; + opcode = 0xCC; + } +} + +/* JCC */ + +PUBLIC void mjcc() +{ + if (jumps_long && opcode < 0x80) /* above 0x80 means loop - not long */ + mbcc(); + else + mshort(); +} + +/* JCXZ, JECXZ */ + +PUBLIC void mjcxz() +{ + if (opcode != defsize) + { + aprefix = 0x67; + ++mcount; /* quick fix - mshort() needs to know */ + } + opcode = 0xE3; + mshort(); + if (aprefix != 0x0) + --mcount; /* quick fix - main routine bumps it again */ +} + +/* LEA */ + +PUBLIC void mlea() +{ + Gv(&source); /* back to front */ + getcomma(); + ++mcount; + getindirect(&target); + yes_samesize(); + buildregular(); +} + +/* MOV */ + +PUBLIC void mmov() +{ + getbinary(); + if (segword >= SEGMOV) + { + oprefix = 0x0; + notimmed(&source); + if (segword > SEGMOV) /* special reg */ + notindirect(&target); + } + if (mcount != 0x0) + { + if (target.base == NOREG && target.index == NOREG && + (source.base == ALREG || source.base == AXREG || + source.base == EAXREG)) + { + opcode = 0xA0 | (direction ^ TOREGBIT) | segword; + lastexp = target.displ; + if ((source.size = displsize(&target)) != defsize) + aprefix = 0x67; + mcount += source.size; + } + else if (source.base == NOREG) + { + if (target.indcount == 0x0) + opcode = 0xB0 | (segword << 0x3) | rm[target.base]; + else + { + buildea(&target); + opcode = 0xC6 | segword; + } + buildimm(&source, FALSE); + } + else + { + if (isspecreg(source.base)) + { + page = PAGE1_OPCODE; + ++mcount; + opcode = 0x0; + } + opcode |= direction | segword; + buildregular(); + } + } +} + +/* MOVSX, MOVZX */ + +PUBLIC void mmovx() +{ + ++mcount; + Gv(&source); + getcomma(); + Ex(&target); + if (target.size == 0x0) + kgerror(SIZE_UNK); + if (target.size > 0x2) + kgerror(ILL_SIZE); + oprefix = 0x0; + if (source.size != defsize) + oprefix = 0x66; + buildsegword(&target); + opcode |= segword; + buildregular(); +} + +/* NEG, NOT */ + +PUBLIC void mnegnot() +{ + ++mcount; + Ex(&target); + buildsegword(&target); + buildunary(0xF6 | segword); +} + +/* OUT */ + +PUBLIC void mout() +{ + ++mcount; + if (opcode & WORDBIT) /* outw; outd not supported */ + mnsize = 0x2; + if (sym == EOLSYM && mnsize != 0x0) + source.size = mnsize; + else + { + if (!getdxreg(&target)) + { + getimmed(&target, 0x1); + opcode -= 0x8; + } + if (sym == COMMA) + { + getsym(); + if (!getaccumreg(&source)) + kgerror(AL_AX_EAX_EXP); + else if (mnsize != 0x0 && regsize[source.base] != mnsize) + error(MISMATCHED_SIZE); + } + else + source.size = regsize[source.base = mnsize < 0x2 ? ALREG : AXREG]; + opcode |= regsegword[source.base]; + } + if (source.size > 0x1 && source.size != defsize) + oprefix = 0x66; +} + +/* POP, PUSH */ + +PUBLIC void mpushpop() +{ + opcode_t oldopcode; + + ++mcount; + getea(&target); + buildsegword(&target); + notbytesize(&target); + if ((oldopcode = opcode) == POP_OPCODE) + { + notimmed(&target); + if (target.base == CSREG) + kgerror(ILL_SEG_REG); + } + if (mcount != 0x0) + { + if (target.indcount == 0x0) + { + if (segword == SEGMOV) + { + switch (target.base) + { + case CSREG: + opcode = 0x0E; + break; + case DSREG: + opcode = 0x1E; + break; + case ESREG: + opcode = 0x06; + break; + case SSREG: + opcode = 0x16; + break; + case FSREG: + opcode = 0xA0; + page = PAGE1_OPCODE; + ++mcount; + break; + case GSREG: + opcode = 0xA8; + page = PAGE1_OPCODE; + ++mcount; + break; + } + if (oldopcode == POP_OPCODE) + ++opcode; + } + else if (target.base != NOREG) + { + opcode = 0x50 | rm[target.base]; + if (oldopcode == POP_OPCODE) + opcode |= 0x8; + } + else + { + opcode = 0x68; + if (oldopcode == POP_OPCODE) + ++opcode; + buildimm(&target, TRUE); + } + } + else + { + buildea(&target); + if (oldopcode == PUSH_OPCODE) + postb |= 0x6 << REG_SHIFT; + } + } +} + +/* RET, RETF */ + +PUBLIC void mret() +{ + ++mcount; + if (sym != EOLSYM) + { + --opcode; + getimmed(&target, 0x2); + } +} + +/* SEG CS/DS/ES/FS/GS/SS */ + +PUBLIC void mseg() +{ + reg_pt reg; + + if (regsegword[reg = regchk()] != SEGMOV) + error(SEG_REG_REQ); + else + { + getsym(); + ++mcount; + opcode = (segoverride - CSREG)[reg]; + } +} + +/* SETCC */ + +PUBLIC void msetcc() +{ + ++mcount; + Eb(&target); + if (mcount != 0x0) + buildea(&target); +} + +/* SHLD, SHRD */ + +PUBLIC void mshdouble() +{ + ++mcount; + Ev(&target); + getcomma(); + Gv(&source); + yes_samesize(); + buildregular(); + getshift(&source2); + lastexp = target.displ; /* getshift() wiped it out */ + if (mcount != 0x0) + { + if (source2.base == CLREG) + opcode |= 0x1; + else + { + source2.size = 0x1; + buildimm(&source2, FALSE); + } + } +} + +/* + TEST + Similar to the regular group1 operators. + It does not allow the sign extended immediate byte forms + and does not use the relevant direction bit. +*/ + +PUBLIC void mtest() +{ + getbinary(); + notsegorspecreg(&source); + if (source.base == NOREG) + { + if (mcount != 0x0) + { + if (target.indcount == 0x0 + && (target.base == ALREG || target.base == AXREG + || target.base == EAXREG)) + opcode = 0xA8 | segword; + else + { + buildea(&target); + opcode = 0xF6 | segword; + } + } + buildimm(&source, FALSE); + } + else + { + opcode |= segword; + buildregular(); + } +} + +/* + XCHG + Similar to the regular group1 operators. + It does not allow any of the immediate forms + and does not use the irrelevant direction bit. +*/ + +PUBLIC void mxchg() +{ + getbinary(); + notimmed(&source); + notsegorspecreg(&source); + if (target.indcount == 0x0) + { + if (target.base == AXREG || target.base == EAXREG) + { + opcode = 0x90 + rm[source.base]; + return; + } + if (source.base == AXREG || source.base == EAXREG) + { + opcode = 0x90 + rm[target.base]; + return; + } + } + opcode |= segword; + buildregular(); +} + +PRIVATE void notbytesize(eap) +register struct ea_s *eap; +{ + if (eap->size == 0x1) + kgerror(ILL_SIZE); +} + +PRIVATE void notimmed(eap) +register struct ea_s *eap; +{ + if (eap->indcount == 0x0 && eap->base == NOREG) + kgerror(ILL_IMM_MODE); +} + +PRIVATE void notindirect(eap) +register struct ea_s *eap; +{ + if (eap->indcount != 0x0) + kgerror(ILL_IND); +} + +PRIVATE void notsegorspecreg(eap) +register struct ea_s *eap; +{ + if (regsegword[eap->base] >= SEGMOV) + kgerror(ILLREG); +} + +PRIVATE void yesimmed(eap) +register struct ea_s *eap; +{ + if (eap->indcount == 0x1) + eap->indcount = 0x0; + if (eap->indcount != 0x0 || eap->base != NOREG) + kgerror(IMM_REQ); +} + +PRIVATE void yes_samesize() +{ + if (target.size == 0x0) + target.size = source.size; + else if (source.size != 0x0 && target.size != source.size) + kgerror(MISMATCHED_SIZE); +} + +#endif /* I80386 */ + +#ifdef MC6809 + +/* 6809 opcode constants */ + +/* bits for indexed addressing */ + +#define INDIRECTBIT 0x10 +#define INDEXBIT 0x80 /* except 5 bit offset */ +#define PCRELBIT 0x04 /* PC relative (in certain cases) */ +#define RRBITS 0x60 /* register select bits */ + +PRIVATE opcode_t rrindex[] = /* register and index bits for indexed adr */ +{ + 0x60 | INDEXBIT, /* S */ + 0x40 | INDEXBIT, /* U */ + 0x00 | INDEXBIT, /* X */ + 0x20 | INDEXBIT, /* Y */ + PCRELBIT | INDEXBIT, /* PC */ +}; + +PRIVATE opcode_t pushpull[] = /* push/pull codes */ +{ + 0x40, /* S */ + 0x40, /* U */ + 0x10, /* X */ + 0x20, /* Y */ + 0x80, /* PC */ + 0x02, /* A */ + 0x04, /* B */ + 0x01, /* CC */ + 0x08, /* DP */ + 0x06, /* D */ +}; + +PRIVATE opcode_t tfrexg1[] = /* transfer/exchange codes for source reg */ +{ + 0x40, /* S */ + 0x30, /* U */ + 0x10, /* X */ + 0x20, /* Y */ + 0x50, /* PC */ + 0x80, /* A */ + 0x90, /* B */ + 0xA0, /* CC */ + 0xB0, /* DP */ + 0x00, /* D */ +}; + +PRIVATE opcode_t tfrexg2[] = /* transfer/exchange codes for target reg */ +{ + 0x04, /* S */ + 0x03, /* U */ + 0x01, /* X */ + 0x02, /* Y */ + 0x05, /* PC */ + 0x08, /* A */ + 0x09, /* B */ + 0x0A, /* CC */ + 0x0B, /* DP */ + 0x00, /* D */ +}; + +FORWARD void checkpostinc P((void)); +FORWARD void doaltind P((void)); +FORWARD void do1altind P((void)); +FORWARD void fixupind P((void)); +FORWARD void getindexnopost P((void)); +FORWARD void inderror P((error_pt errnum)); +FORWARD reg_pt indreg P((reg_pt maxindex)); +FORWARD void predec1 P((void)); +FORWARD void sustack P((reg_pt stackreg)); + +PRIVATE void checkpostinc() +{ + if (sym == ADDOP) + { + if (postb & INDIRECTBIT) + inderror(ILLMOD); /* single-inc indirect illegal */ + else + { + lastexp.offset &= 0xFF00; /* for printing if postbyte is 0: ,X+ */ + getsym(); + } + } + else if (sym == POSTINCOP) + { + postb |= 0x1; + getsym(); + } + else + postb |= 0x4; + fixupind(); +} + +/* common code for all-mode ops, alterable-mode ops, indexed ops */ + +PRIVATE void doaltind() +{ + mcount += 0x2; + if (sym == LBRACKET) + { + postb = INDIRECTBIT; + getsym(); + do1altind(); + if (sym != RBRACKET) + error(RBEXP); + } + else + do1altind(); +} + +PRIVATE void do1altind() +{ + bool_t byteflag; /* set if direct or short indexed adr forced */ + char *oldlineptr; + char *oldsymname; + reg_pt reg; + bool_t wordflag; /* set if extended or long indexed adr forced*/ + + if ((reg = regchk()) != NOREG) + { + switch (reg) + { + case AREG: + postb |= 0x86; + break; + case BREG: + postb |= 0x85; + break; + case DREG: + postb |= 0x8B; + break; + default: + if (indreg(MAXINDREG) != NOREG) + checkpostinc(); + return; + } + getsym(); + if (sym != COMMA) + inderror(COMEXP); + else + getindexnopost(); + return; + } + else if (sym == SUBOP) /* could be -R or - in expression */ + { + oldlineptr = lineptr; /* save state */ + oldsymname = symname; + getsym(); + reg = regchk(); + lineptr = oldlineptr; + symname = oldsymname; + if (reg != NOREG) + { + predec1(); /* it's -R */ + return; + } + sym = SUBOP; + } + else if (sym == COMMA) + { + postb |= INDEXBIT; + getsym(); + if (sym == SUBOP) + { + predec1(); + return; + } + else if (sym != PREDECOP) + { + if (indreg(MAXINDREG) != NOREG) + checkpostinc(); + return; + } + } + if (sym == PREDECOP) + { + postb |= 0x83; + getindexnopost(); + return; + } + + /* should have expression */ + + wordflag = byteflag = FALSE; + if (sym == LESSTHAN) + { + /* context-sensitive, LESSTHAN means byte-sized here */ + byteflag = TRUE; + getsym(); + } + else if (sym == GREATERTHAN) + { + /* context-sensitive, GREATERTHAN means word-sized here */ + wordflag = TRUE; + getsym(); + } + expres(); + if (sym == COMMA) + { /* offset from register */ + getsym(); + if ((reg = indreg(PCREG)) == NOREG) + return; + postb |= 0x8; /* default 8 bit offset */ + if (reg == PCREG) + { + reldata(); + if (!(lastexp.data & (RELBIT | UNDBIT))) + { + lastexp.offset = lastexp.offset - lc; + if (page != 0x0) + lastexp.offset -= 0x4; /* extra for instruction */ + else + lastexp.offset -= 0x3; /* 3 byte instruction + assuming 8 bit offset */ + } + } + if (byteflag) + { + if (!(lastexp.data & (RELBIT | UNDBIT)) && + !is8bitsignedoffset(lastexp.offset)) + error(ABOUNDS); /* forced short form is impossible */ + ++mcount; + } + else if (wordflag || lastexp.data & (FORBIT | RELBIT | UNDBIT) || + !is8bitsignedoffset(lastexp.offset)) + { /* 16 bit offset */ + if (postb & PCRELBIT && !(lastexp.data & RELBIT)) + --lastexp.offset; /* instruction 1 longer than already + allowed */ + postb |= 0x1; + mcount += 0x2; + } + else if (!(postb & PCRELBIT) && + (offset_t) (lastexp.offset + 0x10) < 0x20 && + !(postb & INDIRECTBIT && lastexp.offset != 0x0)) + { /* 5 bit offset */ + postb &= RRBITS | INDIRECTBIT; + if (lastexp.offset == 0x0) + postb |= 0x84; /* index with zero offset */ + else + postb |= (lastexp.offset & 0x1F); + } + else /* 8 bit offset */ + ++mcount; + fixupind(); + } + else if (postb & INDIRECTBIT) + { /* extended indirect */ + postb = 0x9F; + mcount += 0x2; + fixupind(); + } + else if (postb & INDEXBIT) + inderror(ILLMOD); /* e.g. LEAX $10 */ + else + { + if (byteflag || !wordflag && !(lastexp.data & (FORBIT | RELBIT)) && + (lastexp.offset >> 0x8) == dirpag) + { /* direct addressing */ + if (opcode >= 0x80) + opcode |= 0x10; + } + else /* extended addressing */ + { + if (opcode < 0x80) + opcode |= 0x70; + else + opcode |= 0x30; + ++mcount; + if (pass2 && (opcode == JSR_OPCODE || opcode == JMP_OPCODE) && + !(lastexp.data & IMPBIT) && + lastexp.offset + (0x81 - 0x3) < 0x101) + /* JSR or JMP could be done with BSR or BRA */ + error(SHORTB); + } + } +} + +PRIVATE void fixupind() +{ + if ((opcode & 0x30) == 0x0) /* change all but LEA opcodes */ + { + if (opcode < 0x80) + opcode |= 0x60; + else + opcode |= 0x20; + } +} + +PRIVATE void getindexnopost() +{ + getsym(); + if (indreg(MAXINDREG) != NOREG) + fixupind(); +} + +PRIVATE void inderror(errnum) +error_pt errnum; +{ + error(errnum); + if (postb & INDIRECTBIT) + sym = RBRACKET; /* fake right bracket to kill further errors */ + fixupind(); +} + +/* check current symbol is an index register (possibly excepting PC) */ +/* if so, modify postbyte RR and INDEXBIT for it, get next sym, return TRUE */ +/* otherwise generate error, return FALSE */ + +PRIVATE reg_pt indreg(maxindex) +reg_pt maxindex; +{ + reg_pt reg; + + if ((reg = regchk()) == NOREG) + inderror(IREGEXP); + else if (reg > maxindex) + { + inderror(ILLREG); + reg = NOREG; + } + else + { + postb |= rrindex[reg]; + getsym(); + } + return reg; +} + +/* all-mode ops */ + +PUBLIC void mall() +{ + if (sym == IMMEDIATE) + mimmed(); + else + malter(); +} + +/* alterable mode ops */ + +PUBLIC void malter() +{ + postb = 0x0; /* not yet indexed or indirect */ + doaltind(); +} + +/* indexed mode ops */ + +PUBLIC void mindex() +{ + postb = INDEXBIT; /* indexed but not yet indirect */ + doaltind(); +} + +/* immediate ops */ + +PUBLIC void mimmed() +{ + opcode_t nybble; + + mcount += 0x2; + if (sym != IMMEDIATE) + error(ILLMOD); + else + { + if (opcode >= 0x80 && ((nybble = opcode & 0xF) == 0x3 || + nybble == 0xC || nybble >= 0xE)) + ++mcount; /* magic for long immediate */ + symexpres(); + if (pass2 && mcount <= 0x2) + { + chkabs(); + checkdatabounds(); + } + } +} + +/* long branches */ + +PUBLIC void mlong() +{ + mcount += 0x3; /* may be 0x0 or 0x1 here */ + expres(); + if (pass2) + { + reldata(); + if (!(lastexp.data & (RELBIT | UNDBIT))) + { + lastexp.offset = lastexp.offset - lc - lcjump; + if (!(lastexp.data & IMPBIT) && + lastexp.offset + 0x81 < 0x101) + error(SHORTB); /* -0x81 to 0x7F, warning */ + } + } +} + +/* PSHS and PULS */ + +PUBLIC void msstak() +{ + sustack(SREG); +} + +/* TFR and EXG */ + +PUBLIC void mswap() +{ + reg_pt reg; + + mcount = 0x2; + if ((reg = regchk()) == NOREG) + error(REGEXP); + else + { + postb = tfrexg1[reg]; + getsym(); + if (sym != COMMA) + error(COMEXP); + else + { + getsym(); + if ((reg = regchk()) == NOREG) + error(REGEXP); + else if ((postb |= tfrexg2[reg]) + & 0x88 && (postb & 0x88) != 0x88) + error(ILLREG); /* registers not of same size */ + } + } +} + +/* PSHU and PULU */ + +PUBLIC void mustak() +{ + sustack(UREG); +} + +PRIVATE void predec1() +{ + if (postb & INDIRECTBIT) + inderror(ILLMOD); /* single-dec indirect illegal */ + else + { + postb |= 0x82; + getindexnopost(); + } +} + +/* common routine for PSHS/PULS/PSHU/PULU */ + +PRIVATE void sustack(stackreg) +reg_pt stackreg; +{ + reg_pt reg; + + mcount = 0x2; + while ((reg = regchk()) != NOREG) + { + if (reg == stackreg) + { + error(ILLREG); /* cannot stack self */ + break; + } + postb |= pushpull[reg]; + getsym(); + if (sym != COMMA) + break; + getsym(); + } +} + +#endif /* MC6809 */ + +/* routines common to all processors */ + +PUBLIC void getcomma() +{ + if (sym != COMMA) + error(COMEXP); + else + getsym(); +} + +/* inherent ops */ + +/* for I80386 */ +/* AAA, AAS, CLC, CLD, CLI, CLTS, CMC, CMPSB, DAA, DAS, HLT, INTO, INSB, */ +/* INVD, */ +/* LAHF, LEAVE, LOCK, LODSB, MOVSB, NOP, OUTSB, REP, REPE, REPNE, REPNZ, */ +/* REPZ, SAHF, SCASB, STC, STD, STI, STOSB, WAIT, WBINVD */ + +PUBLIC void minher() +{ + ++mcount; +} + +/* short branches */ + +PUBLIC void mshort() +{ + nonimpexpres(); + mshort2(); +} + +PRIVATE void mshort2() +{ + mcount += 0x2; + if (pass2) + { + reldata(); + if (lastexp.data & RELBIT) + showrelbad(); + else if (!(lastexp.data & UNDBIT)) + { + lastexp.offset = lastexp.offset - lc - mcount; + if (!is8bitsignedoffset(lastexp.offset)) + error(ABOUNDS); + } + } +} + +/* check if current symbol is a register, return register number or NOREG */ + +PRIVATE reg_pt regchk() +{ + register struct sym_s *symptr; + + if (sym == IDENT) + { + if ((symptr = gsymptr)->type & MNREGBIT) + { + if (symptr->data & REGBIT) + { +#ifdef I80386 + if (symptr->value_reg_or_op.reg == ST0REG && !fpreg_allowed) + error(FP_REG_NOT_ALLOWED); +#endif + return symptr->value_reg_or_op.reg; + } + } + else if (!(symptr->type & (LABIT | MACBIT | VARBIT))) + symptr->data |= FORBIT; /* show seen in advance */ + } + return NOREG; +} + +/* convert lastexp.data for PC relative */ + +PRIVATE void reldata() +{ + if ((lastexp.data ^ lcdata) & (IMPBIT | RELBIT | SEGM)) + { + if ((lastexp.data ^ lcdata) & RELBIT) + showrelbad(); /* rel - abs is weird, abs - rel is bad */ + else + { + pcrflag = OBJ_R_MASK; + lastexp.data = (lcdata & ~SEGM) | lastexp.data | RELBIT; + /* segment is that of lastexp.data */ + } + } + else /* same file, segment and relocation */ + lastexp.data = (lastexp.data | lcdata) & ~(RELBIT | SEGM); +} -- cgit v1.2.1