$title ('INSTRUCTION MODULE') instruc: do; /* This is the module to decode and produce code- output of a single instruction, possibly preceded by a number of PREFIX-instructions. */ $include (:f1:macro.lit) $include (:f1:struc.lit) $include (:f1:cmacd.lit) $include (:f1:equals.lit) $include (:f1:ermod.lit) $include (:f1:subr1.ext) $include (:f1:expr.ext) $include (:f1:symb.ext) $include (:f1:scan.ext) $include (:f1:ermod.ext) $include (:f1:cmsubr.ext) $include (:f1:instr.x86) $eject dcl /* global variables */ bytevar based macroptr byte, /* byte within codemacro */ comtab(12) byte data /* legal codemacro commands */ (mdbn,mdbf,mdwn,mdwf,mddf,mrelb,mrelw,mmodrm1,mmodrm2,msegfix, mnosegfix,mdbit); $eject /* generate instruction output code */ makecode: proc byte; if (noerror:=searchformatch) then$do /* matching operands, comput code */ do while (bytevar <> mendm) and noerror; do case commandtype(bytevar,length(comtab),.comtab); call mDBNrout; call mDBFrout; call mDWNrout; call mDWFrout; /* typed during earthquake */ call mDDFrout; call mRELBrout; call mRELWrout; call mMODRM1rout; call mMODRM2rout; call mSEGFIXrout; call mNOSEGFIXrout; call mDBITrout; do; end; /* dummy, should not happen */ end$case; end$while; end$if; if noerror then call emit; else call emitdummies; return noerror; end makecode; /* scan all PREFIX instructions */ prefixscan: proc byte; /* compute address of first codemacro */ findmacroaddr: proc; dcl macrop based codemacroptr address; firstmacroptr=macrop; end findmacroaddr; /* test if instruction is of PREFIX type */ prefixinstr: proc byte; dcl ptr address,flag based ptr byte; ptr=firstmacroptr+2; return ((flag and prefix$on) <> 0); end prefixinstr; call findmacroaddr; /* compute pointer to first macro */ do while prefixinstr; if makecode then; /* generate output code,always succed */ call clearcmindex; if findcodemacro(acclen,.accum(0),.codemacroptr) then$do call scan; call findmacroaddr; else$do call errmsg(missinstr); /* missing instruction */ call skip$rest$of$line; return false; end$if; end$while; return true; end prefixscan; /* get all instruction operands */ getoperands: proc byte; dcl moreoperands byte,pt address,oper based pt operandstruc, exitvalue byte; exitvalue=true; nooper=0; /* clear no of operands */ moreoperands=not emptyline; do while moreoperands; moreoperands=false; pt=.operands(nooper); if not operand then$do if oper.stype <> udefsymb then call errmsg(illioper); exitvalue=false; if skip$until(',') then moreoperands=true; else$do if specialtoken(',') then$do call scan; /* skip "," */ if nooper < 3 then moreoperands=true; end$if; end$if; nooper=nooper+1; end$while; return exitvalue; end getoperands; /* test if operands contain enough type information */ enough$type$info: proc byte; dcl pt address,oper based pt operandstruc,(i,flag) byte; flag=true; i=0ffh; do while (i:=i+1) < nooper; pt=.operands(i); if oper.stype=variable then$do if (oper.sflag and typebit) = 0 then flag=false; end$if; end$while; if flag then return true; i=0ffh; /* one of operands lacks type info,check others */ do while (i:=i+1) < nooper; pt=.operands(i); if (oper.sflag and typebit) <> 0 then return true; if (oper.stype=number) and (wrdtest(oper.offset)) then return true; end$while; return false; end enough$type$info; /* Module entry point: */ instruction: proc public; /* decode line in pass 1 and pass 2 */ call clearcmindex; /* clear buffer for output codes */ if prefixscan then$do if getoperands then$do if enough$type$info then$do if makecode then$do if not emptyline then$do call errmsg(end$of$line$err); end$if; else$do call errmsg(opmismatch); end$if; else$do call errmsg(misstypeinfo); call emitdummies; end$if; else$do if makecode then; /* try to make code with bad operands */ end$if; end$if; call skip$rest$of$line; end instruction; end$module instruc;