--- /dev/null
+/*\r
+ * D-Group Assembler for MMURTL (DOS Version).\r
+ *\r
+ * Copyright 1991,1992,1993,1994 R.A. Burgess\r
+\r
+ Version 1.2 11/20/93 - major rewrite on instruction table\r
+ Version 1.3 8/28/94 - Clear macro buf on level 1 to 0 transition\r
+ Version 1.4 9/29/94 - Smashed bug in 66| prefix for string commands\r
+ Version 1.5 10/5/94 - Optimized a couple of commands and fixed\r
+ bug in ENTER X,X instruction. This version seems\r
+ really stable ("yeaaaaa Right," he says...)\r
+ Actually it is....\r
+ 10/29/94 Fix problem with sign extending bytes on ADD\r
+ Version 1.6 12/31/94 - Removed temp files on succesful assemble\r
+ */\r
+\r
+#define U32 unsigned long\r
+#define S32 long\r
+#define U16 unsigned int\r
+#define S16 int\r
+#define U8 unsigned char\r
+#define S8 char\r
+\r
+\r
+#include <ctype.h>\r
+#include <stdio.h>\r
+#include <string.h>\r
+#include <stdlib.h>\r
+#include "dasm.h"\r
+#include "runfile.h"\r
+\r
+/* variables */\r
+\r
+#define LEVELS 5\r
+U8 level = 0; /* current include level */\r
+U32 lineno[LEVELS]; /* line number being parsed */\r
+U8 fContinue = 0; /* True if just returned from include */\r
+\r
+char srcname[LEVELS][40]; /* also active include filenames */\r
+char runname[40];\r
+char lstname[40];\r
+\r
+/* File handles for all files */\r
+\r
+FILE *src_fh[5] = {0,0,0,0,0}; /* Current source file */\r
+FILE *run_fh = 0; /* Current .RUN, .DLL, or .DDR (output) */\r
+FILE *ds_fh = 0; /* temp file for ALL DS strorage */\r
+FILE *cs_fh = 0; /* temp file for ALL CS code */\r
+FILE *lst_fh = 0; /* List file */\r
+FILE *sym_fh = 0; /* Symbol file for debugger */\r
+\r
+char *csname = "CS.TMP";\r
+char *dsname = "DS.TMP";\r
+\r
+U8 filetype = 1; /* 1 = RUN, 2 = DLL, 3 = DDR */\r
+\r
+U8 fListA = 0; /* True if detailed list file */\r
+U8 fListE = 0; /* True if Error only list file */\r
+U8 fSymDump = 0; /* True if we add symbols to the list file */\r
+U8 Column = 0; /* where are we on the LIST line */\r
+U16 error_count = 0;\r
+U16 warn_count = 0;\r
+\r
+\r
+ /* Max input line is 132, but 200 allows plenty for macro subs */\r
+S8 line_buf0[200]; /* Two buffers are swapped during macro substitution */\r
+S8 line_buf1[200];\r
+S8 *line_ptr; /* pointer to next char on line */\r
+\r
+S8 list_buf[200]; /* Used to hold line string for list file */\r
+S8 fLineIn =0; /* TRUE is list_buf has something to list */\r
+\r
+S8 TString[133]; /* all parsed tokens are placed here in text form */\r
+S16 CBString; /* size of parsed token */\r
+S16 TSymnum; /* Symbol table entry number, else 0 */\r
+U32 TNumber; /* value of numeric token */\r
+S16 TInst; /* Instruction number, else 0 */\r
+S16 TReg; /* Register number, else 0 */\r
+S16 Token; /* Token type (also returned from parse) */\r
+S8 fPutBack = 0; /* TRUE (non=zero) if last token was not used */\r
+\r
+S8 LTString[133]; /* Duplicates of Token storage for ReturnToken(); */\r
+S16 LCBString;\r
+S16 LTSymnum;\r
+U32 LTNumber;\r
+S16 LTInst;\r
+S16 LTReg;\r
+S16 LToken;\r
+\r
+S8 UString[31]; /* Place to save unknown labels for Forward Reference */\r
+S16 UCBString; /* Size of Unknown label */\r
+\r
+/* The two Symbol tables have 5 entries; Type, Size, Pointer to Name,\r
+ Segment Offset, and Line.\r
+ As each symbol is found, it's identifed by type, and the name\r
+ is moved to the packed symbol buffer. A pointer is added to the\r
+ table to point to the name in the buffer, while it's size, type,\r
+ segment offset, and line number are added to the table.\r
+ Macro names are also stored in the symbol table, but offset entry\r
+ for a macro indicates it's offset in the Macro buffer.\r
+*/\r
+\r
+/* Variables for symbol tables */\r
+\r
+/* Global Symbol Table */\r
+\r
+#define SYMSMAX 500\r
+#define SYMBUFMAX 10140 /* Avg of 10 byte per name, 700 Max */\r
+\r
+struct symtab {\r
+ U16 Type; /* Token (e.g, CLabel) */\r
+ U16 Line; /* Line symbol was declared on */\r
+ U8 Size; /* Size of symbol name */\r
+ S8 *Ptr; /* Pointer to name in packed buffer */\r
+ U32 Offs; /* Offset in segment */\r
+ };\r
+\r
+struct symtab gst[SYMSMAX]; /* storage for the GST */\r
+\r
+/* S8 SymBuf[SYMBUFMAX]; */ /* Where names are stored. Will be Alloced */\r
+S8 *pSymBuf; /* ptr to allocated buffer */\r
+\r
+S8 *pSymNext; /* ptr to next new entry in symbol buffer */\r
+S16 iSymNext = 1; /* index to next new symbol table entry. */\r
+ /* Starts at 1 - zero it reserved because */\r
+ /* Parse returns 0 for EOL */\r
+\r
+S8 fPublic = 0;\r
+S8 fExtern = 0;\r
+S8 fFarLabel = 0;\r
+\r
+/*********** Local Symbol Table *************/\r
+\r
+/* This is cleared after each include file from level 1 is closed */\r
+/* Clearing means we reset *pLSymNext to begining of buffer */\r
+/* and reset iLSymNext to 1. This "hides" local symbols. */\r
+\r
+#define LSYMSMAX 1800\r
+#define LSYMBUFMAX 16384 /* Avg of 7 bytes per name */\r
+\r
+struct symtab lst[LSYMSMAX]; /* storage for the LST */\r
+\r
+/* S8 LSymBuf[LSYMBUFMAX]; */ /* Where names are stored.*/\r
+S8 *pLSymBuf; /* for allocated buffer */\r
+\r
+S8 *pLSymNext; /* ptr to next new entry in symbol buffer */\r
+S16 iLSymNext = 1; /* index to next new symbol table entry. */\r
+ /* Starts at 1 - zero it reserved because */\r
+ /* Parse returns 0 for EOL */\r
+\r
+/************* Forward Ref Table *********************************/\r
+/*\r
+ Labels that are encountered as forward references are\r
+ stored in this table. When we run across a forward, we do\r
+ not know what segment they are refering to unless it is from\r
+ a jump, call, or loop instruction. We will NOT know for many\r
+ items until they are actually declared. After all the code\r
+ and data has been processed, we go through this table\r
+ and fix all the unknown references using the relative\r
+ The type of forward references are:\r
+\r
+ 1) DSEG DWORD item refers to UNK item (?Seg MemRef)\r
+ 2) CSEG DWORD item refers to UNK item (?Seg MemRef)\r
+ 3) CSEG to CSEG relative 8 (Jump, Jc, or Loop)\r
+ 4) CSEG to CSEG relative 32 (Jump or Call)\r
+\r
+ MOTE: If a calculation is made with the unknown reference, 0\r
+ is used in the calculation. We ALWAYS ADD the value we stored\r
+ with what is found when the reference is resolved.\r
+\r
+*/\r
+\r
+#define FREFSMAX 32768/12\r
+#define FREFTABMAX 32768\r
+#define FREFBUFMAX 16384\r
+\r
+/* Types of forward references. */\r
+\r
+#define DSEGREF 1 /* 32 bit Abs Ref in DSeg, to what is unknown! */\r
+#define CSEGREF 2 /* 32 bit Abs Ref in CSeg, to what is unknown! */\r
+#define CCR32REF 3 /* 32 bit Relative in CSeg */\r
+#define CCR8REF 4 /* 8 bit Relative in CSeg */\r
+\r
+struct forreftab {\r
+ U8 Type; /* 1, 2, 3, or 4 */\r
+ U8 NameSz; /* Size of ref name */\r
+ U16 Line; /* Line reference was made on (for error if not found) */\r
+ S8 *Ptr; /* Pointer to name in packed buffer */\r
+ S32 Offs; /* Offset in segment were it should go */\r
+ };\r
+\r
+struct forreftab *pfrt; /* pointer to allocated table */\r
+\r
+S8 *pRefBuf;\r
+S8 *pRefNext; /* ptr to next new entry in symbol buffer */\r
+S16 iRefNext = 0; /* index to next new forward ref table entry. */\r
+\r
+/************ External Reference table ************/\r
+\r
+/* External definitions that are encountered in a module are\r
+ first entered in the Global Symbol Table (GST) as externals\r
+ if they haven't already been defined (public) by the module\r
+ that owns them.\r
+ When a reference is made to an external, we see if the public has\r
+ already been defined. If so, we resolve it immediately. If not,\r
+ we make an entry in the External Reference Table (ERT). The\r
+ entry has the following 4 pieces of information:\r
+ - Line where reference was made.\r
+ - Index to place holder entry in GST.\r
+ - Segment where reference was made (boolean - TRUE for code seg).\r
+ - Offset in that segment where the resolution will be made.\r
+ With this information we can reslove all the external references\r
+ before we write the code segment to the run file.\r
+*/\r
+\r
+#define EREFSMAX 400\r
+\r
+struct extreftab {\r
+ U8 Type; /* Type of reference so we know how to apply it */\r
+ U16 iSym; /* Index of gst entry. Hi bit seg if CSeg ref */\r
+ U32 Offs; /* Offset in segment were ref needs 32 bit fixing */\r
+ };\r
+\r
+struct extreftab ert[FREFSMAX];\r
+\r
+S16 iERefNext = 0; /* index to next external ref table entry. */\r
+\r
+U16 nExtRef;\r
+\r
+/*********** Fix Up Table *********************/\r
+\r
+/* This table holds 6 types of fixups along with the offset\r
+ in the segment to be fixed up, and if applicable, an index\r
+ to the DLL public name in the GST (which should be defined\r
+ as EXTRNDLL):\r
+ - Fixup type\r
+ - Ref in CSEG to address in DSEG\r
+ - Ref in CSEG to address in CSEG\r
+ - Ref in DSEG to address in DSEG\r
+ - Ref in DSEG to address in CSEG\r
+ - CSEG DLL near 32 bit call used\r
+ - CSEG DLL near 32 bit call defined\r
+ - Offset of 32 bit reference to be resolved\r
+ - Index to DLL public name in GST (if applicable)\r
+\r
+ With this information we can supply the loader with the TAG entries\r
+ in the RUN file needed to resolve them. Most of these entries will\r
+ be made as we parse the code, but many will also be added after\r
+ we fix the forward references because we won't know what segment\r
+ the reference is made to until then.\r
+*/\r
+\r
+#define FIXUPSMAX 32768/7\r
+#define FIXUPBUFMAX 32768\r
+\r
+struct futab {\r
+ U8 type; /* Type of fixup C0, C1, C2, C3, C5, or C8 */\r
+ U32 Offs; /* Offset in segment for 32 bit fixup */\r
+ U16 iSym; /* index of DLL entry in gst, else 0 */\r
+ };\r
+\r
+struct futab *pfut; /* pointer to allocated Fix Up Table */\r
+\r
+S16 iFUNext = 0; /* index to next fix up table entry. */\r
+ /* Starts at 0 */\r
+\r
+U16 nCDFix = 0;\r
+U16 nDDFix = 0;\r
+U16 nDCFix = 0;\r
+U16 nCCFix = 0;\r
+\r
+/********* Macro variables *******************/\r
+\r
+#define MACSMAX 200\r
+#define MACBUFMAX 3000\r
+\r
+S8 *rgMacPtr[MACSMAX]; /* pointer to simple macros */\r
+S8 *pMacBuf;\r
+S8 *pMacNext; /* ptr to next new entry in macro buffer */\r
+S16 iMacNext = 0; /* index to next new symbol entry */\r
+\r
+/* Variables for current segment address offset tracking */\r
+\r
+S8 fStart = 0; /* True if they gave a start address */\r
+S32 StartAddr = 0; /* Filled in when .START is encountered */\r
+S32 oNextData = 0; /* Tracks current DSEG offset */\r
+S32 oNextCode = 0; /* Tracks current CSEG offset */\r
+S32 CodeOffset = 0; /* From Virtual Command */\r
+S32 DataOffset = 0; /* From Virtual Command */\r
+S32 *pNextAddr = 0; /* Points to current segment offset counter */\r
+S8 fDataSeg = 0; /* True if parsing DSEG, else parsing CSEG */\r
+S32 StackTotal = 0; /* Total Stack Specified in Code segs */\r
+\r
+/******************************************************************\r
+ Variables for RAW operands in an instruction.\r
+ These are used when we read in and separate each part of the\r
+ operands so it can be evaluated.\r
+*/\r
+\r
+S16 rgToken[3][20]; /* Raw tokens in the operand (as many as 20) */\r
+S32 rgVal[3][20]; /* value if token is number/displacement */\r
+S16 rgTID[3][20]; /* Register ID if token is a register */\r
+S16 rgTCnt[3]; /* total count of tokens in raw operand */\r
+\r
+/******************************************************************\r
+ These variables are filled in while parsing and evaluating\r
+ instructions that have been read in.\r
+ They have all the info needed to\r
+ encode the instruction into the object module and\r
+ produce FixUp Records if needed.\r
+*/\r
+\r
+/* These are used in the description of all OPERANDS for the current\r
+ instruction we are working on.\r
+*/\r
+S16 rgOpType[3]; /* Operand type for compare to instruction */\r
+S16 rgOpReg[3]; /* If reg only, this which one */\r
+S8 OpSize[3]; /* Operand size for first two (fByte, fWord, fFar etc.) */\r
+S8 OpSizeA; /* Overall operand size for instruction */\r
+S8 OpPrefix; /* Bit set for a segment prefix (fESp etc.) */\r
+S16 iInstEntry; /* Which entry is it in rgINS */\r
+S16 CrntInst; /* instruction we are working on */\r
+S16 InstPfx; /* Special Insturction prefix for crnt inst */\r
+S16 nOperands; /* number of operands we found */\r
+S8 fForRef; /* Crnt inst makes a Forward Reference */\r
+\r
+/* The following vars are used if we have a memory reference that is\r
+ encoded as part of the instruction.\r
+*/\r
+S8 OpMType; /* Mem type (compared to rgM32). 0 if not mem type */\r
+S16 OpBase; /* Base register if fBase is true */\r
+S16 OpIndx; /* Index register if fIndx is true */\r
+S32 OpDisp; /* Displacement if fDisp8 or fDisp32 is TRUE */\r
+S16 iMemEntry; /* If mem operand, which entry in rgM32 */\r
+\r
+/* The following are used if we have immediate values to be encoded as\r
+part of the instruction. Immediates can also be addresses such as\r
+those in Direct and Relative Jumps and Calls!\r
+*/\r
+S32 OpImm; /* Immediate value if fOpImm is true */\r
+S8 fOpImm; /* If OpImm has a value */\r
+S32 OpImm2; /* Second Imm value for iSAD and other multi-Imm types */\r
+S8 fOpImm2; /* If OpImm2 has a value */\r
+\r
+/* This is set for each type of fixup required after an instruction\r
+line. Data fixups are done directly in the code that generates\r
+storage in DSeg. */\r
+\r
+U8 nFixUp; /* Fixup number (Cx) */\r
+\r
+/*************************************************************************/\r
+\r
+/* In the final stages of building an instruction, these contain the\r
+ fragment bytes of encoded instructions (along with flags for\r
+ optional parts used).\r
+*/\r
+\r
+U8 bOpc1; /* Zero if not used */\r
+U8 bOpc2; /* Always used */\r
+U8 bModRM; /* ModRM byte value if used */\r
+U8 bSIB; /* SIB value if used */\r
+S8 fModRM; /* True if bModRM is used */\r
+S8 fSIB; /* True if bSIB is used */\r
+\r
+/*** These are used in the expression parser ******/\r
+\r
+U8 ExpType; /* 0 = Forward, 1 = Local, 2 = Global, 3 = Current Addr */\r
+U8 ExpType0;\r
+S16 nExpSyms; /* Used by the numeric expression evaluator */\r
+S16 iExpSym, iExpSym0; /* if a symbol value translates to a SYMOFF,\r
+ this holds the symbol table index. */\r
+S8 fOffset; /* True if derived from an Offset */\r
+\r
+/* Variables for Storage allocation */\r
+\r
+\r
+S8 fMoreStorage = 0; /* True when storage continues to next line */\r
+S16 StoreSize = 0;\r
+\r
+/**** Variables for building the RUN File (DLL or Device Driver) ********/\r
+\r
+/* Once we have the CS and DS tmp files run through to correct any external\r
+ variables or forward labels, we build the run file. This is done\r
+ by building the tag records, sending them followed by the proper data\r
+ for each one.\r
+*/\r
+\r
+struct tagtype tag;\r
+\r
+\r
+/******************* END VARIABLES - BEGIN CODE ********************/\r
+\r
+/* ANSI prototypes for all functions are in DProtos.h */\r
+\r
+#include "DProtos.h"\r
+\r
+\r
+/***************************************************************/\r
+/* Write a DWord to the current segment and update the counter */\r
+/***************************************************************/\r
+\r
+void OutDWord(unsigned long Data)\r
+{\r
+unsigned char *pOut, b;\r
+int i;\r
+ pOut = &Data;\r
+ if (fDataSeg) {\r
+ for (i=0; i<4; i++) {\r
+ b = *pOut++;\r
+ fputc(b , ds_fh);\r
+ }\r
+ oNextData+=4;\r
+ }\r
+ else {\r
+ for (i=0; i<4; i++) {\r
+ b = *pOut++;\r
+ fputc(b , cs_fh);\r
+ }\r
+ oNextCode+=4;\r
+ }\r
+}\r
+\r
+/******************************************************************/\r
+/* Write a DWord to the current segment and DO NOT update counter */\r
+/******************************************************************/\r
+\r
+void OutDWordCS(unsigned long Data)\r
+{\r
+unsigned char *pOut, b;\r
+int i;\r
+ pOut = &Data;\r
+ for (i=0; i<4; i++) {\r
+ b = *pOut++;\r
+ fputc(b , cs_fh);\r
+ }\r
+}\r
+\r
+/******************************************************************/\r
+/* Write a DWord to the current segment and DO NOT update counter */\r
+/******************************************************************/\r
+\r
+void OutDWordDS(unsigned long Data)\r
+{\r
+unsigned char *pOut, b;\r
+int i;\r
+ pOut = &Data;\r
+ for (i=0; i<4; i++) {\r
+ b = *pOut++;\r
+ fputc(b , ds_fh);\r
+ }\r
+}\r
+\r
+/**************************************************************/\r
+/* Write a Word to the current segment and update the counter */\r
+/**************************************************************/\r
+\r
+void OutWord(unsigned int Data)\r
+{\r
+unsigned char *pOut, b;\r
+int i;\r
+ pOut = &Data;\r
+ b = *pOut++;\r
+ if (fDataSeg) {\r
+ fputc(b , ds_fh);\r
+ b = *pOut;\r
+ fputc(b , ds_fh);\r
+ oNextData+=2;\r
+ }\r
+ else {\r
+ fputc(b , cs_fh);\r
+ b = *pOut;\r
+ fputc(b , cs_fh);\r
+ oNextCode+=2;\r
+ }\r
+}\r
+\r
+/**************************************************************/\r
+/* Write a BYTE to the current segment and update the counter */\r
+/**************************************************************/\r
+\r
+void OutByte(unsigned char Data)\r
+{\r
+ if (fDataSeg) {\r
+ fputc(Data , ds_fh);\r
+ oNextData++;\r
+ }\r
+ else {\r
+ fputc(Data , cs_fh);\r
+ oNextCode++;\r
+ }\r
+}\r
+\r
+/*****************************************************************/\r
+/* Write a BYTE to the current segment and DO NOT update counter */\r
+/*****************************************************************/\r
+\r
+void OutByteCS(unsigned long Data)\r
+{\r
+char b;\r
+ b = Data;\r
+ fputc(b , cs_fh);\r
+}\r
+\r
+/* All the "grunt work" functions are in dasmq.c */\r
+\r
+#include "DASMq.c"\r
+\r
+/*********************************************\r
+This searches the Reference table for the name\r
+described by pb, cb. It only compares items that\r
+are the same length (cb == TRefSize[x]).\r
+It returns the number or 0 if not found.\r
+**********************************************/\r
+\r
+S16 findref(S8 *pb, S16 cb) /* pointer to, and size of string */\r
+{\r
+S16 i;\r
+S8 name[132];\r
+\r
+strncpy(name, pb, cb); /* move name local */\r
+name[cb] = 0; /* null terminate */\r
+\r
+i = iRefNext;\r
+while (i>0) { /* backwards through forward ref table */\r
+ i--;\r
+ /* Only compare if same size */\r
+ if (pfrt[i].NameSz == cb) {\r
+ if (strncmp(name, pfrt[i].Ptr, cb) == 0) return(i);\r
+ }\r
+}\r
+return(0);\r
+}\r
+\r
+\r
+/*****************************************************\r
+ Evaluates only single token operands and sets up\r
+ globals so EvalOper can finish the job.\r
+ The actual value or register is left in\r
+ rgToken[op][0], and the type is placed\r
+ in rgTempl[op][0] for a memory operand.\r
+*****************************************************/\r
+S16 EvalOper1(S16 op)\r
+{\r
+S16 i;\r
+U16 symtype;\r
+\r
+ /* Set up symtype up front in case it's needed */\r
+\r
+ if (ExpType == 1) /* Local */\r
+ symtype = lst[iExpSym].Type;\r
+ else if (ExpType == 2) { /* global */\r
+ if (gst[iExpSym].Type & tEXTRN)\r
+ nExtRef = iExpSym;\r
+ symtype = gst[iExpSym].Type;\r
+ }\r
+ else symtype = 0;\r
+\r
+ switch (rgToken[op][0]) {\r
+ case REGIST:\r
+ if (is_r32(rgTID[op][0])) rgOpType[op] = r32;\r
+ else if (is_r16(rgTID[op][0])) rgOpType[op] = r16;\r
+ else if (is_r8(rgTID[op][0])) rgOpType[op] = r8;\r
+ else if (is_rCRG(rgTID[op][0])) rgOpType[op] = rCRG;\r
+ else if (is_rDRG(rgTID[op][0])) rgOpType[op] = rDRG;\r
+ else if (is_rTRG(rgTID[op][0])) rgOpType[op] = rTRG;\r
+ else if (is_rSEG(rgTID[op][0])) rgOpType[op] = rSEG;\r
+ rgOpReg[op] = rgTID[op][0];\r
+ break;\r
+ case NUMBER:\r
+ if ((rgVal[op][0] >= -128) && (rgVal[op][0] <= 127))\r
+ rgOpType[op] = val8;\r
+ else if ((rgVal[op][0] >= -32768) && (rgVal[op][0] <= 32767))\r
+ rgOpType[op] = val16;\r
+ else rgOpType[op] = val32;\r
+ if (!fOpImm) {\r
+ OpImm = rgVal[op][0];\r
+ fOpImm = 1;\r
+ }\r
+ else {\r
+ OpImm2 = rgVal[op][0];\r
+ fOpImm2 = 1;\r
+ }\r
+ break;\r
+ case NUMOFF: /* OFFSET var name. IMMEDIATE VALUE. */\r
+ OpSize[op] = fDWord;\r
+ rgOpType[op] = val32;\r
+ OpImm = rgVal[op][0];\r
+ fOpImm = 1;\r
+ if (symtype & CLABEL)\r
+ nFixUp = CCFIXTAG;\r
+ else if (symtype & DLABEL)\r
+ nFixUp = CDFIXTAG;\r
+ if (!symtype)\r
+ fForRef = 1;\r
+ break;\r
+ case SYMOFF: /* Check for ALL jump, call & Loop instructions */\r
+\r
+ if (ExpType == 1) /* Local */\r
+ symtype = lst[iExpSym].Type;\r
+ else if (ExpType == 2) { /* global */\r
+ if (gst[iExpSym].Type & tEXTRN)\r
+ nExtRef = iExpSym;\r
+ symtype = gst[iExpSym].Type;\r
+ }\r
+ else /* Unknown - Forward */\r
+ symtype = 0;\r
+\r
+ if (((CrntInst >= xJA) &&\r
+ (CrntInst <= xJZ)) ||\r
+ (CrntInst == xCALL)) {\r
+\r
+ if (OpSize[op] & fShort)\r
+ rgOpType[op] = rel8;\r
+ else\r
+ rgOpType[op] = relW;\r
+ OpImm = rgVal[op][0];\r
+ fOpImm = 1;\r
+ }\r
+\r
+ else if ((CrntInst >= xLOOP) && (CrntInst <= xLOOPZ)) {\r
+ rgOpType[op] = rel8;\r
+ OpImm = rgVal[op][0];\r
+ fOpImm = 1;\r
+ }\r
+ else {\r
+ rgOpType[op] = mem;\r
+ OpMType |= fDisp32;\r
+ OpDisp = rgVal[op][0];\r
+ if (symtype & CLABEL)\r
+ nFixUp = CCFIXTAG;\r
+ else if (symtype & DLABEL)\r
+ nFixUp = CDFIXTAG;\r
+ }\r
+ if (!symtype)\r
+ fForRef = 1;\r
+ break;\r
+ default:\r
+ line_error(15);\r
+ return(0);\r
+ } /* switch */\r
+\r
+/* print_Oper(op); Testing only... */\r
+\r
+return(1);\r
+}\r
+\r
+/*********** EvalOper *******************************\r
+ Evaluates the array of reserved words, registers,\r
+ numbers, etc. that should make up an operand.\r
+ For single token operands it's easy! BUT for memory\r
+ operands it gets a little more complicated.\r
+ For memory operands we look for key sequences of\r
+ tokens that make up the "effective address" as\r
+ described in the Intel documentation, then see if\r
+ we have all the pieces to make one (EA).\r
+ This returns 1 if we can classify the operand and\r
+ there were no errors. The type of operand we find\r
+ (e.g., r8, r16, r32, val8, val16, val32, mem,\r
+ relW, etc.) is placed in rgOpType[op].\r
+ This calls EvalOper1() to handle single token\r
+ oprerands and evaluates multiple token operands\r
+ internally. The reason we break single token operands\r
+ out in a separate call is for speed and clarity\r
+ of the code.\r
+ Special handling is required for for JMP, Jcond,\r
+ and CALL instructions because they may be using\r
+ a forward reference not yet defined. This is the\r
+ only case where such a reference is allowed.\r
+*****************************************************/\r
+\r
+S16 EvalOper(S16 op)\r
+{\r
+S16 i;\r
+S8 fDone, fOpenSQ, fError;\r
+U16 symtype;\r
+/*\r
+These are the Raw operands:\r
+S16 rgToken[3][20]; Raw tokens in the operand\r
+S32 rgVal[3][20]; value if token is number/displacement\r
+S16 rgTID[3][20]; Register ID if token is a register\r
+S16 rgTCnt[3]; total count of tokens in raw operand\r
+\r
+ This is what is produced:\r
+*/\r
+\r
+rgOpType[op] = 0; /* int - Operand type for compare to instruction */\r
+rgOpReg[op] = 0; /* If reg only, this which one */\r
+\r
+i = 0; /* index into raw tokens */\r
+fError = 0; /* set true for invalid operand error */\r
+fDone = 0; /* Set when no more tokens are expected in operand */\r
+fOpenSQ = 0; /* keep track of [] */\r
+\r
+/* flags for segment instruction prefix - NONE unless otherwise set */\r
+/* If it's a single token operand, take the fast, easy way out! */\r
+\r
+if (rgTCnt[op] == 1) {\r
+ return (EvalOper1(op));\r
+}\r
+\r
+else { /* multiple tokens in operand */\r
+\r
+ /* with more than 1 token it is usually a memory reference\r
+ but not always. We will default to mem and change those we\r
+ find that aren't. */\r
+\r
+ rgOpType[op] = mem;\r
+\r
+ /* Segment prefix? If so, set flag and eat 2 tokens */\r
+\r
+ if ((rgToken[op][0]==REGIST) && (is_rSEG(rgTID[op][0]))) {\r
+ if (rgToken[op][1] == COLON) {\r
+ switch (rgToken[op][0]) {\r
+ case rDS: OpPrefix |= fDSp; break;\r
+ case rES: OpPrefix |= fESp; break;\r
+ case rSS: OpPrefix |= fSSp; break;\r
+ case rFS: OpPrefix |= fFSp; break;\r
+ case rGS: OpPrefix |= fGSp; break;\r
+ case rCS: OpPrefix |= fCSp; break;\r
+ default:;\r
+ }\r
+ i += 2; /* skip rSEG and colon */\r
+ }\r
+ else {\r
+ line_error(16);\r
+ return(0);\r
+ }\r
+ }\r
+\r
+/* Loop through the raw tokens looking for Base Reg, Index Reg,\r
+ Scale value, or displacement and setting varaibles as needed.\r
+*/\r
+\r
+ while ((i < rgTCnt[op]) &&\r
+ (!fError) &&\r
+ (!fDone)) {\r
+ switch (rgToken[op][i]) {\r
+\r
+ case REGIST:\r
+ if (is_r32(rgTID[op][i])) { /* check for Indx & Base Reg */\r
+ if (rgToken[op][i+1] == STAR) { /* Index w/Scale */\r
+ if (!(OpMType & fIndx)) { /* still OK */\r
+ OpMType |= fIndx;\r
+ OpIndx = rgTID[op][i];\r
+ if (rgToken[op][i+2] == NUMBER) {\r
+ switch (rgVal[op][i+2]) {\r
+ case 2: OpMType |= fScale2; break;\r
+ case 4: OpMType |= fScale4; break;\r
+ case 8: OpMType |= fScale8; break;\r
+ default:\r
+ line_error(17);\r
+ fError = 1;\r
+ }\r
+ }\r
+ else {\r
+ line_error(18);\r
+ fError = 1;\r
+ }\r
+ }\r
+ else {\r
+ line_error(19);\r
+ fError = 1;\r
+ }\r
+ i+=3; /* get past *NUMBER */\r
+ }\r
+ /* Must be base, unless fBase true, then try Index */\r
+ else {\r
+ if (!(OpMType & fBase)) { /* Base for sure */\r
+ OpMType |= fBase;\r
+ OpBase = rgTID[op][i];\r
+ i++;\r
+ }\r
+ else { /* try Index */\r
+ if (!(OpMType & fIndx)) { /* It's free, use it */\r
+ OpMType |= fIndx;\r
+ OpIndx = rgTID[op][i];\r
+ i++;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ else { /* must be 32 bit general purpose register */\r
+ line_error(20);\r
+ fError = 1;\r
+ }\r
+ break;\r
+\r
+\r
+ case SYMOFF: /* One symbol was used by itself or in an expression */\r
+ if (ExpType == 1) /* Local */\r
+ symtype = lst[iExpSym].Type;\r
+ else if (ExpType == 2) { /* global */\r
+ if (gst[iExpSym].Type & tEXTRN)\r
+ nExtRef = iExpSym;\r
+ symtype = gst[iExpSym].Type;\r
+ }\r
+ else /* Unknown - Forward */\r
+ symtype = 0;\r
+\r
+ if (OpMType & (fDisp32|fDisp8)) { /* Already a disp! */\r
+ line_error(21);\r
+ fError = 1;\r
+ }\r
+\r
+ /* Check for conditional jumps. */\r
+\r
+ else if ((CrntInst >= xJA) &&\r
+ (CrntInst <= xJZ) &&\r
+ (CrntInst != xJMP) &&\r
+ (!(fOpenSQ)))\r
+ {\r
+ if (OpSize[op] & fShort)\r
+ rgOpType[op] = rel8;\r
+ else rgOpType[op] = relW;\r
+ if (fOpImm) {\r
+ OpImm2 = rgVal[op][i];\r
+ fOpImm2 = 1;\r
+ }\r
+ else {\r
+ OpImm = rgVal[op][i];\r
+ fOpImm = 1;\r
+ }\r
+ if (!symtype)\r
+ fForRef = 1;\r
+ }\r
+\r
+ /* Check for JMP */\r
+\r
+ else if (CrntInst == xJMP) /* && (!(fOpenSQ))) */\r
+ {\r
+ if ((OpSize[op] & fFar) || (symtype & tFAR)) {\r
+ rgOpType[op] = iSAD;\r
+ if (fOpImm) {\r
+ OpImm2 = rgVal[op][i];\r
+ fOpImm2 = 1;\r
+ }\r
+ else {\r
+ OpImm = rgVal[op][i];\r
+ fOpImm = 1;\r
+ }\r
+ }\r
+ else if (OpSize[op] & fShort) {\r
+ rgOpType[op] = rel8;\r
+ OpImm = rgVal[op][i];\r
+ fOpImm = 1;\r
+ if (!symtype)\r
+ fForRef = 1;\r
+ }\r
+ else if (OpSize[op] & fFWord) {\r
+ rgOpType[op] = memF; /* memF = 32 disp which has 16:32 */\r
+ OpMType |= fDisp32;\r
+ OpDisp = rgVal[op][i];\r
+ if (symtype & CLABEL)\r
+ nFixUp = CCFIXTAG;\r
+ else if (symtype & DLABEL)\r
+ nFixUp = CDFIXTAG;\r
+ if (!symtype)\r
+ fForRef = 1;\r
+ }\r
+ else {\r
+ rgOpType[op] = relW;\r
+ OpImm = rgVal[op][i];\r
+ fOpImm = 1;\r
+ if (!symtype)\r
+ fForRef = 1;\r
+ }\r
+ }\r
+\r
+ /* Check for CALL */\r
+\r
+ else if ((CrntInst == xCALL) && (!(fOpenSQ)))\r
+ {\r
+ if ((OpSize[op] & fFar) || (symtype & tFAR)) {\r
+ rgOpType[op] = iSAD;\r
+ if (fOpImm) {\r
+ OpImm2 = rgVal[op][i];\r
+ fOpImm2 = 1;\r
+ }\r
+ else {\r
+ OpImm = rgVal[op][i];\r
+ fOpImm = 1;\r
+ }\r
+ }\r
+ else if (OpSize[op] & fFWord) {\r
+ rgOpType[op] = memF; /* memF = 32 disp which has 16:32 */\r
+ OpMType |= fDisp32;\r
+ OpDisp = rgVal[op][i];\r
+ if (symtype & CLABEL)\r
+ nFixUp = CCFIXTAG;\r
+ else if (symtype & DLABEL)\r
+ nFixUp = CDFIXTAG;\r
+ if (!symtype)\r
+ fForRef = 1;\r
+ }\r
+ else { /* Relative call */\r
+ rgOpType[op] = relW;\r
+ if (!symtype)\r
+ fForRef = 1;\r
+ }\r
+ }\r
+\r
+ /* Check for SGDT SIDT */\r
+\r
+ else if ((CrntInst == xSGDT) || (CrntInst == xSIDT))\r
+ {\r
+ if (OpSize[op] & fFWord) {\r
+ rgOpType[op] = memF; /* memF = 32 disp which has 16:32 */\r
+ OpMType |= fDisp32;\r
+ OpDisp = rgVal[op][i];\r
+ if (symtype & CLABEL)\r
+ nFixUp = CCFIXTAG;\r
+ else if (symtype & DLABEL)\r
+ nFixUp = CDFIXTAG;\r
+ if (!symtype)\r
+ fForRef = 1;\r
+ }\r
+ }\r
+\r
+ /* Check for Loop */\r
+\r
+ else if ((CrntInst >= xLOOP) && (CrntInst <= xLOOPZ))\r
+ {\r
+ rgOpType[op] = rel8;\r
+ OpImm = rgVal[op][0];\r
+ fOpImm = 1;\r
+ if (!symtype)\r
+ fForRef = 1;\r
+ }\r
+ else {\r
+ OpDisp = rgVal[op][i];\r
+ OpMType |= fDisp32;\r
+ if (symtype & CLABEL)\r
+ nFixUp = CCFIXTAG;\r
+ else if (symtype & DLABEL)\r
+ nFixUp = CDFIXTAG;\r
+ if (!symtype)\r
+ fForRef = 1;\r
+ }\r
+ i++;\r
+ break;\r
+\r
+ case NUMBER: /* can be 8 or 32 bit disp, or hard address */\r
+ OpDisp = rgVal[op][i];\r
+ if ((rgVal[op][i] >= -128) && (rgVal[op][i] <= 127))\r
+ OpMType |= fDisp8;\r
+ else\r
+ OpMType |= fDisp32;\r
+ i++;\r
+ break;\r
+\r
+ case OPENSQR:\r
+ if (fOpenSQ) {\r
+ line_error(23);\r
+ fError = 1;\r
+ }\r
+ else fOpenSQ = 1;\r
+ i++;\r
+ break;\r
+ case CLOSSQR:\r
+ if (!fOpenSQ) {\r
+ line_error(24);\r
+ fError = 1;\r
+ }\r
+ else fOpenSQ = 0;\r
+ i++;\r
+ break;\r
+ case COLON: /* for far addresses */\r
+ i++;\r
+ break;\r
+ case PLUS:\r
+ i++;\r
+ break;\r
+ case rBYTE:\r
+ if ((!OpSize[op]) && (rgToken[op][i+1] == rPTR)) {\r
+ OpSize[op] |= fByte;\r
+ i+=2;\r
+ }\r
+ else {\r
+ line_error(25);\r
+ fError = 1;\r
+ }\r
+ break;\r
+ case rWORD:\r
+ if ((!OpSize[op]) && (rgToken[op][i+1] == rPTR)) {\r
+ OpSize[op] |= fWord;\r
+ i+=2;\r
+ }\r
+ else {\r
+ line_error(25);\r
+ fError = 1;\r
+ }\r
+ break;\r
+ case rDWORD:\r
+ if ((!OpSize[op]) && (rgToken[op][i+1] == rPTR)) {\r
+ OpSize[op] |= fDWord;\r
+ i+=2;\r
+ }\r
+ else {\r
+ line_error(25);\r
+ fError = 1;\r
+ }\r
+ break;\r
+ case rFWORD:\r
+ if ((!OpSize[op]) && (rgToken[op][i+1] == rPTR)) {\r
+ OpSize[op] |= fFWord;\r
+ i+=2;\r
+ }\r
+ else {\r
+ line_error(25);\r
+ fError = 1;\r
+ }\r
+ break;\r
+ case rNEAR:\r
+ if ((!OpSize[op]) && (rgToken[op][i+1] == rPTR)) {\r
+ OpSize[op] |= fNear;\r
+ i+=2;\r
+ }\r
+ else {\r
+ line_error(25);\r
+ fError = 1;\r
+ }\r
+ break;\r
+ case rFAR:\r
+ if ((!OpSize[op]) && (rgToken[op][i+1] == rPTR)) {\r
+ OpSize[op] |= fFar;\r
+ i+=2;\r
+ }\r
+ else {\r
+ line_error(25);\r
+ fError = 1;\r
+ }\r
+ break;\r
+ case rSHORT:\r
+ if (!OpSize[op]) {\r
+ OpSize[op] |= fShort;\r
+ i++;\r
+ }\r
+ else {\r
+ line_error(25);\r
+ fError = 1;\r
+ }\r
+ break;\r
+ default: {\r
+ line_error(32);\r
+ fprintf(lst_fh, " %d ", rgToken[op][i]); /* TESTING */\r
+ i++;\r
+ }\r
+\r
+ } /* switch */\r
+ } /* while */\r
+}\r
+if (fError) return(0);\r
+if ((fDone) && (i< rgTCnt[op])) {\r
+ line_error(33);\r
+ return(0);\r
+ }\r
+\r
+return(1);\r
+\r
+}\r
+\r
+/********************************************\r
+ Adds ALL forward reference to the Ref table.\r
+ This holds references to all foward addresses\r
+ (unknown) in the current module.\r
+ This stores all Refs UPPER case.\r
+*********************************************/\r
+void ForRef(U8 type, S32 Offset)\r
+{\r
+S16 i;\r
+\r
+if (pRefNext >= (pRefBuf + FREFBUFMAX))\r
+ fatal_error("Forward Reference buffer overflow...");\r
+if (iRefNext >= FREFSMAX)\r
+ fatal_error("Forward Reference table overflow...");\r
+\r
+/* Make a forward reference table entry */\r
+\r
+strncpy(pRefNext, UString, UCBString);\r
+pfrt[iRefNext].NameSz = UCBString; /* size of name */\r
+pfrt[iRefNext].Ptr = pRefNext;\r
+pfrt[iRefNext].Line = lineno[level]; /* for error reporting */\r
+pfrt[iRefNext].Type = type; /* type of ref */\r
+\r
+\r
+pfrt[iRefNext].Offs = Offset; /* Offset to correction in CS or DS */\r
+\r
+/* update for next symbol */\r
+\r
+pRefNext += UCBString;\r
+iRefNext++;\r
+\r
+}\r
+\r
+/********************************************\r
+ Adds fixup table entries to be placed in\r
+ the run file. This includes DLL entries.\r
+*********************************************/\r
+\r
+void FixUp(U8 typef, S32 Offset, U16 iSymbol)\r
+{\r
+\r
+if (typef == CDFIXTAG)\r
+ nCDFix++;\r
+else if (typef == DDFIXTAG)\r
+ nDDFix++;\r
+else if (typef == DCFIXTAG)\r
+ nDCFix++;\r
+else if (typef == CCFIXTAG)\r
+ nCCFix++;\r
+\r
+\r
+if (iFUNext >= FIXUPSMAX)\r
+ fatal_error("Fixup Table overflow...");\r
+pfut[iFUNext].type = typef;\r
+pfut[iFUNext].Offs = Offset;\r
+pfut[iFUNext].iSym = iSymbol; /* global symbol entry for DLL */\r
+\r
+iFUNext++;\r
+\r
+}\r
+\r
+/********************************************\r
+ Adds External Reference to table.\r
+ This DOES NOT includes DLL Refs.\r
+ ETypes are the same as ForRef types\r
+ except there and no 8 bit externals.\r
+*********************************************/\r
+\r
+void ExtRef(U8 EType, U16 iSymbol)\r
+{\r
+\r
+if (iERefNext >= EREFSMAX)\r
+ fatal_error("External Reference Table overflow...");\r
+\r
+if (fDataSeg)\r
+ ert[iERefNext].Offs = oNextData;\r
+else {\r
+ ert[iERefNext].Offs = oNextCode;\r
+ }\r
+ert[iERefNext].iSym = iSymbol; /* global symbol entry for external */\r
+ert[iERefNext].Type = EType; /* global symbol entry for external */\r
+\r
+iERefNext++;\r
+}\r
+\r
+/*****************************************************\r
+ Reads in all of the reserved words, numbers, math\r
+ operators, etc. that make up one operand. They are\r
+ read into one of 3 2D arrays as indicated by "op".\r
+ Integer rgTCnt[op] is number if items. A special\r
+ case for jump and call instructions is tested if\r
+ we end up with an Unknown Symbol as and operand.\r
+ We Error out if we have an UNKSYM without a\r
+ jump or call.\r
+*****************************************************/\r
+\r
+S16 GetOper(S16 op)\r
+{\r
+S16 i, T;\r
+\r
+i = 0;\r
+while (1) {\r
+ T = Parse();\r
+ switch (T) {\r
+ case ZERO:\r
+ rgTCnt[op] = i;\r
+ if (i) return(1);\r
+ else return(0);\r
+ case REGIST:\r
+ rgTID[op][i] = TReg;\r
+ rgToken[op][i] = T;\r
+ break;\r
+ case NUMBER: /* check for special case of REG*2,*4,*8 */\r
+ if ((i > 1) &&\r
+ (rgToken[op][i-1] == STAR) &&\r
+ (rgToken[op][i-2] == REGIST)) {\r
+ rgVal[op][i] = TNumber;\r
+ rgToken[op][i] = T;\r
+ break; /* only break here if we find special case */\r
+ } /* Else fall thru to Expression */\r
+ case LSYMBOL:\r
+ case SYMBOL:\r
+ case DOLLAR: /* These should all evaluate to a number!! */\r
+ case OPENRND:\r
+ case MINUS:\r
+ case UNKSYM:\r
+ case rOFFSET:\r
+ if (Expression()) {\r
+ rgVal[op][i] = TNumber;\r
+ rgToken[op][i] = Token; /* Token instead of T (From Expr)*/\r
+ }\r
+ else {\r
+ line_error(35);\r
+ return(0);\r
+ }\r
+\r
+ break;\r
+ case COMMA:\r
+ if (!i) {\r
+ line_error(36);\r
+ return(0);\r
+ }\r
+ rgTCnt[op] = i;\r
+ ReturnToken();\r
+ return(1);\r
+ case OPENSQR:\r
+ case CLOSSQR:\r
+ case STAR:\r
+ case PLUS:\r
+ case SLASH:\r
+ case SEMI:\r
+ case COLON:\r
+ case rFAR:\r
+ case rBYTE:\r
+ case rWORD:\r
+ case rDWORD:\r
+ case rFWORD:\r
+ case rPTR:\r
+ case rSHORT:\r
+ rgToken[op][i] = T;\r
+ break;\r
+ default:\r
+ line_error(38);\r
+ return(0);\r
+ }\r
+ i++;\r
+} /* while */\r
+}\r
+\r
+/********************************************\r
+ This finds the first matching entry in rgINS\r
+ by first matching the instruction number,\r
+ then matching operands. The table is indexed\r
+ with an array providing the first entry for\r
+ the instruction. This speed things up a bit.\r
+*********************************************/\r
+\r
+S16 INSEntry(S16 InsNum, S16 nOpers)\r
+{\r
+S16 i;\r
+\r
+ i = rgInsLookUp[InsNum];\r
+ while (i <= nrgINS) {\r
+\r
+ /* instruction entries of the same type\r
+ are all kept together. This is an early out.\r
+ */\r
+\r
+ if (rgINS[i][0] != InsNum)\r
+ return(0); /* couldn't find a match at all... */\r
+\r
+ /* See if all the operators match by calling is_Comp for each.\r
+ */\r
+\r
+ if ((is_Comp(i,0)) &&\r
+ (is_Comp(i,1)) &&\r
+ (is_Comp(i,2)))\r
+\r
+ return(i); /* yes, they all match! */\r
+\r
+ i++; /* No, goto next entry */\r
+ }\r
+}\r
+\r
+\r
+/********************************************\r
+ EmitInst spits out the instruction bytes that\r
+ were encoded into variables by EncodeInst.\r
+ This handles output to the code segment\r
+ file as well as the text to the list file.\r
+ It updates the code segment address and\r
+ also adds fixup records as they are needed.\r
+\r
+The instruction (up to 16 bytes) is ordered\r
+as follows:\r
+ Instruction Prefix 0 or 1 byte\r
+ Address Size Prefix 0 or 1 byte\r
+ Operand Prefix 0 or 1 byte\r
+ Segment Override 0 or 1 bytes\r
+ Opcode 1 or 2 bytes\r
+ MODR/M 0 or 1 bytes\r
+ SIB 0 or 1 bytes\r
+ Displacement 0,1,2 or 4 bytes\r
+ Immediate 0,1,2, or 4 bytes\r
+**********************************************/\r
+\r
+void EmitInst(void)\r
+{\r
+U8 oppfx;\r
+S8 sbyte;\r
+S16 sword;\r
+U16 i; /* used local to each section if needed */\r
+\r
+\r
+\r
+ /*\r
+ Instruction prefix: 0 or 1 byte (Lock, Rep, etc.)\r
+ */\r
+\r
+ if (InstPfx) {\r
+ if (InstPfx==xLOCK) {\r
+ if (fListA) {\r
+ Column += 2;\r
+ put_hexb(0x0F, lst_fh);\r
+ }\r
+ OutByte(0xF0);\r
+ }\r
+ else if ((InstPfx==xREPNE) || (InstPfx==xREPNZ)) {\r
+ if (fListA) {\r
+ Column += 2;\r
+ put_hexb(0xF2, lst_fh);\r
+ }\r
+ OutByte(0xf2);\r
+ }\r
+ else { /* Must be REP... */\r
+ if (fListA) {\r
+ Column += 2;\r
+ put_hexb(0xF3, lst_fh);\r
+ }\r
+ OutByte(0xf3);\r
+ }\r
+ if (fListA)\r
+ Column += fprintf(lst_fh, "| ");\r
+ }\r
+\r
+/*\r
+ Skip Address Size prefix: (67h) cause we aren't\r
+ doing USE16, nor do we support 16 bit addressing modes!\r
+*/\r
+\r
+/* Operand Size prefix: 0 or 1 (66h) */\r
+\r
+ if (OpSizeA & fWord) {\r
+ if (fListA) {\r
+ Column += 2;\r
+ put_hexb(0x66, lst_fh);\r
+ Column += fprintf(lst_fh, "| ");\r
+ }\r
+ OutByte(0x66);\r
+ }\r
+\r
+/* Segment Override prefix */\r
+\r
+ switch (OpPrefix) {\r
+ case fDSp: oppfx = 0x3e; break;\r
+ case fESp: oppfx = 0x26; break;\r
+ case fSSp: oppfx = 0x36; break;\r
+ case fFSp: oppfx = 0x64; break;\r
+ case fGSp: oppfx = 0x65; break;\r
+ case fCSp: oppfx = 0x2e; break;\r
+ default: oppfx = 0;\r
+ }\r
+ if (oppfx) {\r
+ if (fListA) {\r
+ Column += 2;\r
+ put_hexb(oppfx, lst_fh);\r
+ Column += fprintf(lst_fh, "| ");\r
+ }\r
+ OutByte(oppfx);\r
+ }\r
+\r
+/* OpCode byte 1 (optional)\r
+ bOpc1 was setup in EncodeInst (either 0 or 0Fh)\r
+*/\r
+\r
+ if (bOpc1) {\r
+ if (fListA) {\r
+ Column += 2;\r
+ put_hexb(bOpc1, lst_fh);\r
+ Column += fprintf(lst_fh, " ");\r
+ }\r
+ OutByte(bOpc1);\r
+ }\r
+\r
+/* OpCode byte 2 (always sent) */\r
+\r
+ if (fListA) {\r
+ Column += 2;\r
+ put_hexb(bOpc2, lst_fh);\r
+ Column += fprintf(lst_fh, " ");\r
+ }\r
+\r
+ OutByte(bOpc2);\r
+\r
+/* ModR/M (optional) */\r
+\r
+ if (fModRM) {\r
+ if (fListA) {\r
+ Column += 2;\r
+ put_hexb(bModRM, lst_fh);\r
+ Column += fprintf(lst_fh, " ");\r
+ }\r
+ OutByte(bModRM);\r
+ }\r
+\r
+/* SIB (optional) */\r
+\r
+ if (fSIB) {\r
+ if (fListA) {\r
+ Column += 2;\r
+ put_hexb(bSIB, lst_fh);\r
+ Column += fprintf(lst_fh, " ");\r
+ }\r
+ OutByte(bSIB);\r
+ }\r
+\r
+/*\r
+ Disp: 0, 1, 2 or 4\r
+ A Displacement is a memory reference (an offset in a segment)\r
+ that is encoded as part of the instruction. The value to encode\r
+ is placed in OpDisp when the instruction is parsed and\r
+ evaluated.\r
+*/\r
+\r
+ if (OpMType & fDisp32) {\r
+\r
+ if (fListA) {\r
+ Column += 8;\r
+ put_hexd(OpDisp, lst_fh);\r
+ if ((nExtRef) || (fForRef))\r
+ Column += fprintf(lst_fh, "r ");\r
+ else\r
+ Column += fprintf(lst_fh, " ");\r
+ }\r
+ if (nExtRef)\r
+ ExtRef(CSEGREF, nExtRef);\r
+ else if (fForRef)\r
+ ForRef(CSEGREF, oNextCode);\r
+ else if (nFixUp)\r
+ FixUp(nFixUp, oNextCode, 0); /* Code ref to data */\r
+ OutDWord(OpDisp);\r
+ }\r
+\r
+ if (OpMType & fDisp8) {\r
+\r
+ if (fListA) {\r
+ sbyte = OpDisp;\r
+ Column += 2;\r
+ put_hexb(sbyte, lst_fh);\r
+ Column += fprintf(lst_fh, " ");\r
+ }\r
+ OutByte(OpDisp);\r
+ }\r
+\r
+/*\r
+ Immediate: 0, 1, 2 or 4\r
+ The type of instruction operands tell us if we must encode\r
+ immediate values as part of the instruction. All instructions\r
+ have only one immediate value except ENTER. We make a check here\r
+ to determine if it is this instruction.\r
+\r
+ imm8 = Immediate Byte in OpImm\r
+ imm16 = immediate 16 bit value in OpImm\r
+ immX = immediate value matching OpSize in OpImm\r
+ rel8 = immediate Byte calculated from a label\r
+ relW = immediate Word (16 or 32) calculated from a label\r
+ iSAD = immediate DWORD:WORD from Far Pointer (OpImm & OpImm2)\r
+\r
+ immv1 is not encoded (implied by instruction)\r
+ immv3 is not encoded (also implied - INT 03 - Debug)\r
+ */\r
+ if (fOpImm) \r
+ {\r
+ if ((rgINS[iInstEntry][1] == immX) ||\r
+ (rgINS[iInstEntry][2] == immX) ||\r
+ (rgINS[iInstEntry][3] == immX))\r
+ {\r
+ if (OpSizeA & fByte)\r
+ {\r
+ if (fListA)\r
+ {\r
+ sbyte = OpImm;\r
+ Column += 2;\r
+ put_hexb(sbyte, lst_fh);\r
+ Column += fprintf(lst_fh, " ");\r
+ }\r
+ OutByte(OpImm);\r
+ }\r
+ else if (OpSizeA & fWord)\r
+ {\r
+ if (fListA) \r
+ {\r
+ sword = OpImm;\r
+ Column += 4;\r
+ put_hexw(sword, lst_fh);\r
+ Column += fprintf(lst_fh, " ");\r
+ }\r
+ OutWord(OpImm);\r
+ }\r
+ else { /* MUST be a DWord */\r
+ if (fListA) {\r
+ Column += 8;\r
+ put_hexd(OpImm, lst_fh);\r
+ if (nFixUp)\r
+ Column += fprintf(lst_fh, "r ");\r
+ else\r
+ Column += fprintf(lst_fh, " ");\r
+ }\r
+ if (nExtRef)\r
+ ExtRef(CSEGREF, nExtRef);\r
+ else if (fForRef)\r
+ ForRef(CSEGREF, oNextCode);\r
+ else if (nFixUp)\r
+ FixUp(nFixUp, oNextCode, 0); /* Code ref to data */\r
+ OutDWord(OpImm);\r
+ }\r
+ }\r
+\r
+ if ((rgINS[iInstEntry][1] == imm16) ||\r
+ (rgINS[iInstEntry][2] == imm16) ||\r
+ (rgINS[iInstEntry][3] == imm16)) {\r
+ if (fListA) {\r
+ Column += 4;\r
+ sword = OpImm;\r
+ put_hexw(sword, lst_fh);\r
+ Column += fprintf(lst_fh, " ");\r
+ }\r
+ OutWord(OpImm);\r
+ }\r
+ else if ((rgINS[iInstEntry][1] == imm8) ||\r
+ (rgINS[iInstEntry][2] == imm8) ||\r
+ (rgINS[iInstEntry][3] == imm8) ||\r
+ (rgINS[iInstEntry][1] == ims8) ||\r
+ (rgINS[iInstEntry][2] == ims8) ||\r
+ (rgINS[iInstEntry][3] == ims8))\r
+ {\r
+ if (fListA) {\r
+ Column += 2;\r
+ sbyte = OpImm;\r
+ put_hexb(sbyte, lst_fh);\r
+ Column += fprintf(lst_fh, " ");\r
+ }\r
+ OutByte(OpImm);\r
+ }\r
+\r
+ /* Special check for Enter. It is only instructon with 2 Imms!*/\r
+\r
+ if (rgINS[iInstEntry][0] == xENTER)\r
+ {\r
+ if (fListA) {\r
+ Column += 2;\r
+ sbyte = OpImm2;\r
+ put_hexb(sbyte, lst_fh);\r
+ Column += fprintf(lst_fh, " ");\r
+ }\r
+ OutByte(OpImm2);\r
+ }\r
+\r
+\r
+ /* With relative values for immediates, OpImm comes in as\r
+ the address of the target jump or call. We must take\r
+ the current code offset (of the next instruction) and\r
+ subtract it from the target (OpImm) to get the relative\r
+ jump value. If it is an UNKSYM we will put the value\r
+ of the target into the FRT to hold it and\r
+ do the math on the second pass of the machine code.\r
+ Math Example:\r
+\r
+ oCode = 100 (next instruction)\r
+ Target = 50\r
+ Jump = -50 (Target-Current)\r
+\r
+ oCode = 100 (next instruction)\r
+ Target = 150\r
+ Jump = 50 (Target-Current)\r
+\r
+ Relative immediate values found in the GST as EXTERN\r
+ require an ERT entry so they can be fixed up when\r
+ the final code module is written to the run file.\r
+\r
+ Relative immediate values found in the GST as PUBLICS\r
+ can be fixed up NOW.\r
+\r
+ Relative immediate values NOT found are assumed local\r
+ and an entry is made in the FRT so they can be fixed\r
+ up when this code module is written to the main\r
+ temp code module.\r
+ */\r
+\r
+ if (rgINS[iInstEntry][1] == relW) {\r
+ if (nExtRef) { /* list external */\r
+ OpImm = 0;\r
+ ExtRef(CCR32REF, nExtRef);\r
+ }\r
+ else if (fForRef) { /* list Forward Relative */\r
+ OpImm = 0;\r
+ ForRef(CCR32REF, oNextCode);\r
+ }\r
+ else { /* Fix known ref */\r
+ OpImm = OpImm - (oNextCode + 4);\r
+ }\r
+\r
+ if (fListA) {\r
+ Column += 8;\r
+ put_hexd(OpImm, lst_fh);\r
+ if ((!fForRef) && (!nExtRef))\r
+ Column += fprintf(lst_fh, " ");\r
+ else\r
+ Column += fprintf(lst_fh, "R ");\r
+ }\r
+ OutDWord(OpImm);\r
+ }\r
+\r
+ if (rgINS[iInstEntry][1] == rel8) {\r
+ if (!fForRef) { /* Fix KNOWN Relative */\r
+ OpImm = OpImm - (oNextCode + 1);\r
+ if ((OpImm > 127) || (OpImm < -127))\r
+ line_error(39);\r
+ }\r
+ else { /* Else List Unknown */\r
+ ForRef(CCR8REF, oNextCode);\r
+ OpImm = 0;\r
+ }\r
+\r
+ if (fListA) {\r
+ Column += 2;\r
+ sbyte = OpImm;\r
+ put_hexb(sbyte, lst_fh);\r
+ if ((!fForRef) && (!nExtRef))\r
+ Column += fprintf(lst_fh, " ");\r
+ else\r
+ Column += fprintf(lst_fh, "R ");\r
+ }\r
+ OutByte(OpImm);\r
+ }\r
+\r
+ if (rgINS[iInstEntry][1] == iSAD) {\r
+ if (fListA) {\r
+ Column += 4;\r
+ sword = OpImm;\r
+ put_hexw(sword, lst_fh);\r
+ Column += fprintf(lst_fh, ":");\r
+ Column += 4;\r
+ put_hexd(OpImm2, lst_fh);\r
+ Column += fprintf(lst_fh, " ");\r
+ }\r
+ OutWord(OpImm);\r
+ OutDWord(OpImm2);\r
+ }\r
+ }\r
+}\r
+\r
+\r
+/********************************************\r
+ This encodes the instructions into bytes\r
+ and calls EmitInst() to put them into the\r
+ current code segment. The instruction can\r
+ be as long as 16 bytes if all options are used.\r
+ The order of the bytes and their possible\r
+ sizes are as follows:\r
+ Inst Prefix: 0 or 1 (Lock, Rep, etc.)\r
+ Address Size prefix: 0 or 1 (67h) - We don't use this\r
+ Operand Size prefix: 0 or 1 (66h)\r
+ Segment Override: 0 or 1\r
+ OpCode: 1 or 2\r
+ ModR/M: 0 or 1\r
+ SIB: 0 or 1\r
+ Disp: 0, 1, 2 or 4\r
+ Immediate: 0, 1, 2 or 4\r
+ This routine follows the guidance to build\r
+ instructions given in the rgINS table\r
+ (as bit flags). It calls EmitInst() to\r
+ emit the code, list-file information and\r
+ fixups to the FUT.\r
+ **********************************************/\r
+void EncodeInst(void)\r
+{\r
+S8 fError;\r
+S16 i;\r
+U8 bTmp;\r
+\r
+/*\r
+U8 bOpc1; Zero if not used THESE ARE GLOBAL...\r
+U8 bOpc2; Always used\r
+U8 bModRM;\r
+U8 bSIB;\r
+S8 fModRM; Is bModRM set/used?\r
+S8 fSIB; Is bSIB set/used?\r
+*/\r
+\r
+fModRM = 0; /* not used by default */\r
+fSIB = 0;\r
+\r
+\r
+/* SKIP the Address Size Prefix for now because we don't do 16 Bit\r
+ Effective addresses\r
+*/\r
+\r
+\r
+/*\r
+ Now we will build the instruction in (up to) 4 temporary bytes.\r
+ We do it in temporary byte vars so we can see if an Operand Prefix\r
+ and a possible address fixup record is required before we\r
+ actually put it into the code segment.\r
+*/\r
+\r
+/*\r
+ The WORD forms of string instructions require us\r
+ to force a WORD size. We set this in the instruction table\r
+ as qUW in byte [4],\r
+*/\r
+\r
+if (rgINS[iInstEntry][4] & qUW)\r
+ OpSizeA |= fWord;\r
+\r
+/* Put in the first byte of Opcode from table (if required). qP0F is\r
+ set in rgINS[iInstEntry][4] if a 0Fh prefix is required for this inst.\r
+ A 0 in bObc1 indicates that this byte is NOT to be used.\r
+*/\r
+\r
+if (rgINS[iInstEntry][4] & qP0F)\r
+ bOpc1 = 0x0F;\r
+else bOpc1 = 0;\r
+\r
+/* Get the Opcode from table into bOpc2 */\r
+\r
+bOpc2 = rgINS[iInstEntry][5];\r
+\r
+/* The flags zMR1, zMR2, zMOP, zAR1, and zAR2 all indicate that the\r
+ ModRM is needed. The following set of if-else statements checks these\r
+ flags and sets REG/OP field of MOD/RM byte if required.\r
+ OpSize should already be set. We also complete\r
+ the instruction encoding (with the exception of any immediate values)\r
+ if the other operand is a register.\r
+*/\r
+\r
+if (rgINS[iInstEntry][7] & zMR1) {\r
+ bModRM = rgINS[iInstEntry][6];\r
+ fModRM = 1;\r
+ if (is_Reg(rgOpType[0]))\r
+ EncodeRegBits(rgOpReg[0], &bModRM, 3);\r
+ if (is_Reg(rgOpType[1])) {\r
+ EncodeRegBits(rgOpReg[1], &bModRM, 0);\r
+ bModRM |= 0xC0; /* indictes REG in RM field */\r
+ }\r
+ }\r
+else if (rgINS[iInstEntry][7] & zMR2) {\r
+ bModRM = rgINS[iInstEntry][6];\r
+ fModRM = 1;\r
+ if (is_Reg(rgOpType[1]))\r
+ EncodeRegBits(rgOpReg[1], &bModRM, 3);\r
+ if (is_Reg(rgOpType[0])) {\r
+ EncodeRegBits(rgOpReg[0], &bModRM, 0);\r
+ bModRM |= 0xC0; /* indictes REG in RM field */\r
+ }\r
+ }\r
+else if (rgINS[iInstEntry][7] & zMOP) {\r
+ bModRM = rgINS[iInstEntry][6];\r
+ fModRM = 1;\r
+ if (is_Reg(rgOpType[0])) {\r
+ EncodeRegBits(rgOpReg[0], &bModRM, 0);\r
+ bModRM |= 0xC0; /* indictes REG in RM field */\r
+ }\r
+ }\r
+else if (rgINS[iInstEntry][7] & zAR1) {\r
+ bTmp = 0;\r
+ EncodeRegBits(rgOpReg[0], &bTmp, 0);\r
+ bOpc2 += bTmp;\r
+ }\r
+else if (rgINS[iInstEntry][7] & zAR2) {\r
+ bTmp = 0;\r
+ EncodeRegBits(rgOpReg[1], &bTmp, 0);\r
+ bOpc2 += bTmp;\r
+ }\r
+else if ((rgINS[iInstEntry][7] & zRG1) && (rgOpType[0] != mem)) {\r
+ bModRM = rgINS[iInstEntry][6];\r
+ fModRM = 1;\r
+ EncodeRegBits(rgOpReg[0], &bModRM, 3);\r
+ bModRM |= 0xC0; /* indictes REG in RM field */\r
+ }\r
+\r
+\r
+ /* OpSize may not be required for many instructions, but we know\r
+ for a fact it MUST be known for memory operands!\r
+ */\r
+\r
+ if ((rgOpType[0] == mem) ||\r
+ (rgOpType[1] == mem) ||\r
+ (rgOpType[0] == memF)) {\r
+ if (!(OpSizeA & (fByte|fWord|fDWord|fFWord))) {\r
+ line_error(40);\r
+ return;\r
+ }\r
+ }\r
+\r
+ /*\r
+ If zORD, see if we have word or dword register and OR the Opcode\r
+ (Opc2) with 01 if so.\r
+ */\r
+\r
+ if (rgINS[iInstEntry][7] & zORD) {\r
+ if (OpSizeA & (fWord | fDWord))\r
+ bOpc2 |= 0x01;\r
+ }\r
+\r
+ /* Perform the following additonal steps if we have a memory reference\r
+ as determined by iMemEntry.\r
+ */\r
+\r
+ fSIB = 0;\r
+ if (iMemEntry) {\r
+\r
+ /* If SIB is needed (as determined from OpMType), get it and also\r
+ OR ModRM by required value from rgM32 table\r
+ */\r
+\r
+ bModRM |= rgM32[iMemEntry][2]; /* Use ModRM 'OR' value from table */\r
+ if (rgM32[iMemEntry][1]) { /* is there an SIB byte? */\r
+ bModRM &= 0x38; /* 00111000 leaves Reg bit on */\r
+ bModRM |= rgM32[iMemEntry][2]; /* 'OR' ModRM with table value */\r
+ bSIB = rgM32[iMemEntry][3];\r
+ fSIB = 1;\r
+ }\r
+\r
+\r
+ /* At this point we have our Opcode, ModRM, and SIB (if required).\r
+ The MOD and SS bit are already filled in from the table.\r
+ This means we just stick the register values or bits for Disp etc\r
+ in the correct positions to complete it.\r
+ If we didn't have an SIB, we either have a single displacement,\r
+ a base or both.\r
+ */\r
+\r
+ if (!fSIB) { /* only a base, disp, or both */\r
+ if (OpMType & fBase)\r
+ EncodeRegBits(OpBase, &bModRM, 0);\r
+ else\r
+ bModRM |= 0x05; /* only a disp32 */\r
+ }\r
+ else {\r
+ if (OpMType & fBase)\r
+ EncodeRegBits(OpBase, &bSIB, 0);\r
+ else bModRM |= 0x20; /* else set [--][--] bits */\r
+ if (OpMType & fIndx)\r
+ EncodeRegBits(OpIndx, &bSIB, 3);\r
+ }\r
+ }\r
+\r
+ EmitInst();\r
+\r
+}\r
+\r
+\r
+/********************************************\r
+ When the dispatcher detects an Instruction\r
+ it calls this code to read in (via parse)\r
+ the parametrs for the instruction and to\r
+ put together the opcodes. First we loop thru\r
+ and get up to 3 operands, then we evaluate\r
+ them (classify by type). Next we look up\r
+ the instruction and find a match for the\r
+ operand types they have specified, and\r
+ finally, we encode the instruction into the\r
+ code segment updating the code segment offset\r
+ pointer.\r
+*********************************************/\r
+void Instruction(void)\r
+{\r
+S16 i;\r
+S8 fError;\r
+S8 OpSizeTmp;\r
+\r
+fError = 0;\r
+if (fDataSeg) {\r
+ line_error(41);\r
+ return;\r
+ }\r
+\r
+/* If the instruction is a prefix instruction, save it\r
+ and Parse again to get the real instruction */\r
+\r
+if ((TInst==xREP) || (TInst==xREPE) || (TInst==xREPZ) ||\r
+ (TInst==xREPNE) || (TInst==xREPNZ) || (TInst==xLOCK)) {\r
+ InstPfx = TInst;\r
+ i = Parse();\r
+ if (i != INSTRU) {\r
+ line_error(42);\r
+ return;\r
+ }\r
+} else InstPfx = 0;\r
+\r
+/* RESET all global instruction variables */\r
+\r
+CrntInst = TInst; /* Save the instruction */\r
+nOperands = 0; /* none yet... */\r
+rgOpType[0] = 0;\r
+rgOpType[1] = 0;\r
+rgOpType[2] = 0;\r
+OpMType = 0; /* char - memory type (a byte to compare to rgM32) */\r
+OpSize[0] = 0; /* char - Mem op size (fByte, fWord, fDword, fFword) */\r
+OpSize[1] = 0; /* char - Mem op size (fByte, fWord, fDword, fFword) */\r
+OpSizeA = 0; /* char - Mem op size (fByte, fWord, fDword, fFword) */\r
+OpSizeTmp = 0; /* char - Mem op size (fByte, fWord, fDword, fFword) */\r
+OpPrefix = 0; /* For Segment register prefix flags */\r
+OpDisp = 0; /* long - Displacement if fDisp8 or fDisp32 is TRUE */\r
+OpBase = 0; /* int - Base register if fBase is true */\r
+OpIndx = 0; /* int - Index register if fIndx is true */\r
+fOpImm = 0; /* No Immediate value yet */\r
+OpImm = 0; /* Default to 0 */\r
+fOpImm2 = 0; /* No second Immediate value yet */\r
+OpImm2 = 0; /* Default to 0 */\r
+nFixUp = 0; /* Fixup type if needed, else 0 */\r
+nExtRef = 0; /* GST entry if external ref was made */\r
+fForRef = 0; /* No Forward Ref in crnt inst yet */\r
+ExpType = 0; /* Type of symbol used in instruction */\r
+ExpType0 = 0; /* Type of symbol used in instruction */\r
+iExpSym = 0; /* Index into symtab for symbol if used */\r
+iExpSym0 = 0; /* Index into symtab for symbol if used */\r
+\r
+if (GetOper(0)) {\r
+ nOperands++;\r
+ ExpType0 = ExpType;\r
+ iExpSym0 = iExpSym;\r
+ if ((Parse()== COMMA)) {\r
+ if (GetOper(1)) {\r
+ nOperands++;\r
+ if ((Parse()== COMMA)) {\r
+ if (GetOper(2)) {\r
+ nOperands++;\r
+ if (Parse()) {\r
+ line_error(33);\r
+ return;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+/*\r
+At this point we have the instruction operands stored in\r
+tokenized form in arrays. We now call EvalOper() which evaluates\r
+the operands and fills in several variables that will assist in\r
+building the instruction. EvalOper() returns 1 if it was a valid\r
+operand, else 0.\r
+*/\r
+\r
+if (nOperands) { /* at least one */\r
+ if (EvalOper(0)) {\r
+ if (nOperands > 1) { /* a second operand */\r
+ if (EvalOper(1)) {\r
+ if (nOperands > 2) { /* a third??? - could be... */\r
+ if (!(EvalOper(2)))\r
+ fError = 1;\r
+ }\r
+ }\r
+ else fError = 1;\r
+ }\r
+ }\r
+ else fError = 1;\r
+}\r
+\r
+if (fError) return;\r
+\r
+/*\r
+ We must check to see what the word size of the instruction is\r
+ by looking at register sizes if any are included in the instruction.\r
+ If there are memory references or immediates involved, OpSizeA\r
+ MUST be set properly else it's an error! When there is a symbol involved\r
+ such as a move to a memory variable, we check the variable size and set\r
+ the OpSize to the variable size. If it's still not set, the line will\r
+ error out when we try to build the instruction because the caller\r
+ should have explicitly set the size (e.g., DWORD PTR ...).\r
+\r
+ If a register is one of the operands in a memory transfer\r
+ (e.g., MOV [mem], EAX) then the move obviously defaults to the size\r
+ of the register (no ifs, ands, or buts).\r
+\r
+ If there is no reg involved, we then look at 'OpSize[i]'\r
+ which may have been set by the size operators (e.g., DWORD PTR).\r
+ If it's zero we look at iExpSym which was set if there was a single\r
+ symbol involved in the memory reference. If there was, then we use it.\r
+ If it is blank, we error out cause we don't know what size memory\r
+ access we are doing!\r
+ This is done for each operand then the two are compared. If one is\r
+ zero we use the other, if both have something but are different\r
+ we error out!\r
+\r
+*/\r
+ /* Find the first operand size */\r
+\r
+ /* First, let's look to see if they forced it! */\r
+\r
+ if (OpSize[0] & (fByte|fWord|fDWord|fFWord))\r
+\r
+ { /* do nothing */ }\r
+\r
+ /* If they didn't force it, we'll look for the register size! */\r
+\r
+ else if (rgOpType[0] == r32) OpSize[0] |= fDWord;\r
+ else if (rgOpType[0] == r16) OpSize[0] |= fWord;\r
+ else if (rgOpType[0] == rSEG) OpSize[0] |= fWord;\r
+ else if (rgOpType[0] == r8) OpSize[0] |= fByte;\r
+\r
+ /* Still nothing, so let's at symbols. */\r
+\r
+ else if (ExpType0 == 1)\r
+ { /* Local symbol */\r
+ if (lst[iExpSym0].Type & sBYTE) OpSize[0] |= fByte;\r
+ else if (lst[iExpSym0].Type & sWORD) OpSize[0] |= fWord;\r
+ else if (lst[iExpSym0].Type & sDWORD) OpSize[0] |= fDWord;\r
+ else if (lst[iExpSym0].Type & sFWORD) OpSize[0] |= fFWord;\r
+ }\r
+ else if (ExpType0 == 2)\r
+ { /* Global Symbol */\r
+ if (gst[iExpSym0].Type & sBYTE) OpSize[0] |= fByte;\r
+ else if (gst[iExpSym0].Type & sWORD) OpSize[0] |= fWord;\r
+ else if (gst[iExpSym0].Type & sDWORD) OpSize[0] |= fDWord;\r
+ else if (gst[iExpSym0].Type & sFWORD) OpSize[0] |= fFWord;\r
+ }\r
+ else if (ExpType0 == 3)\r
+ OpSize[0] |= fDWord; /* $ defaults to DWord */\r
+\r
+\r
+ /* Find the second operand size. Check "forced fit" first */\r
+\r
+ if (OpSize[1] & (fByte|fWord|fDWord|fFWord))\r
+ { /* do nothing */ }\r
+\r
+ else if (rgOpType[1] == r32) OpSize[1] |= fDWord;\r
+ else if (rgOpType[1] == r16) OpSize[1] |= fWord;\r
+ else if (rgOpType[1] == rSEG) OpSize[1] |= fWord;\r
+ else if (rgOpType[1] == r8) OpSize[1] |= fByte;\r
+\r
+ /* No registers, so let's look to see if they forced it! */\r
+\r
+ /* Still nothing, so let's at symbols. */\r
+\r
+ else if (ExpType == 1)\r
+ { /* Local symbol */\r
+ if (lst[iExpSym].Type & sBYTE) OpSize[1] |= fByte;\r
+ else if (lst[iExpSym].Type & sWORD) OpSize[1] |= fWord;\r
+ else if (lst[iExpSym].Type & sDWORD) OpSize[1] |= fDWord;\r
+ else if (lst[iExpSym].Type & sFWORD) OpSize[1] |= fFWord;\r
+ }\r
+ else if (ExpType == 2)\r
+ { /* Global Symbol */\r
+ if (gst[iExpSym].Type & sBYTE) OpSize[1] |= fByte;\r
+ else if (gst[iExpSym].Type & sWORD) OpSize[1] |= fWord;\r
+ else if (gst[iExpSym].Type & sDWORD) OpSize[1] |= fDWord;\r
+ else if (gst[iExpSym].Type & sFWORD) OpSize[1] |= fFWord;\r
+ }\r
+ else if (ExpType == 3)\r
+ OpSize[1] |= fDWord; /* $ defaults to DWord */\r
+\r
+ /* Special cases for operand size matching. */\r
+\r
+ if (CrntInst == xOUT)\r
+ OpSize[0] = OpSize[1];\r
+\r
+\r
+/*\r
+ Now that have the operands, and we know the TYPE of data (fByte etc.)\r
+ we call INSEntry to find the matching\r
+ entry in the array that describes each instruction. If we don't\r
+ find one that matches we error out telling them they have bad\r
+ operands.\r
+*/\r
+\r
+/* find first matching entry in rgINS */\r
+\r
+ iInstEntry = INSEntry(CrntInst, nOperands);\r
+\r
+ if (!iInstEntry) {\r
+ line_error(44);\r
+ return;\r
+ }\r
+\r
+ /* Now we make sure that we have set all operand sizes\r
+ and check for special cases as defined in rgINS.\r
+ */\r
+\r
+ if (rgINS[iInstEntry][7] & zSIZ)\r
+ OpSize[1] = OpSize[0];\r
+\r
+ if (!OpSize[1])\r
+ OpSize[1] = OpSize[0];\r
+\r
+ if (!OpSize[0])\r
+ OpSize[0] = OpSize[1];\r
+\r
+ /* Give them an error if operand sizes don't match */\r
+\r
+ if (nOperands > 1)\r
+ if (OpSize[0] != OpSize[1]) {\r
+ line_error(43);\r
+ return;\r
+ }\r
+\r
+ OpSizeA = OpSize[0]; /* Set primary operand size */\r
+\r
+/* If either the first or second operand was memory, we have to find\r
+ which entry in rgM32 it matches before we can encode it. If none\r
+ matches it is an invalid memory operand. If neither is a mem operand\r
+ we set iMemEntry to zero. There is the special case of moffs type\r
+ which is a short form of displacmement when moving data to and from thew\r
+ accumulator (e.g., MOV EAX, VAR1). We check for this and skip the\r
+ mem check if this is the instruction type we are on.\r
+*/\r
+\r
+ if ((rgINS[iInstEntry][1] == moff) || (rgINS[iInstEntry][2] == moff))\r
+ iMemEntry = 0;\r
+ else if ((rgOpType[0]==mem) ||\r
+ (rgOpType[1]==mem) ||\r
+ (rgOpType[0]==memF))\r
+ {\r
+\r
+ for (i=1; i<nrgM32; i++) {\r
+ if (OpMType == rgM32[i][0]) break;\r
+ }\r
+\r
+ /* if i is off the end of the array we\r
+ didn't find an entry that matched\r
+ */\r
+\r
+ if (i==nrgM32) {\r
+ line_error(45);\r
+ return;\r
+ }\r
+ else iMemEntry = i;\r
+ }\r
+ else iMemEntry = 0;\r
+\r
+/*\r
+ At this point we should have all information we need to actually\r
+ encode the instruction (unless it's a forward ref). So we call EncodeInst.\r
+*/\r
+\r
+EncodeInst();\r
+\r
+\r
+}\r
+\r
+\r
+/********************************************\r
+ Create Storage in current segment. At this\r
+ point we should see a storage statement as\r
+ the current token followed by a number (or\r
+ string if DB). If string (DB) we insert\r
+ single byte values (one per char) into the\r
+ segment.\r
+*********************************************/\r
+void Storage(void)\r
+{\r
+S32 TSave, NSave, nDUP;\r
+S16 i, j, sword;\r
+S8 fColon, fExpectColon, fComma, fDUP;\r
+U16 symtype;\r
+\r
+fDUP = 0;\r
+nDUP = 1; /* default duplicate value */\r
+fComma = 0;\r
+fColon = 0;\r
+fExpectColon = 0;\r
+\r
+if (!fMoreStorage) { /* is it a continuation of previous line? */\r
+ switch(Token) { /* parse returns Token */\r
+ case rDB:\r
+ StoreSize = 1;\r
+ break;\r
+ case rDW:\r
+ StoreSize = 2;\r
+ break;\r
+ case rDD:\r
+ StoreSize = 4;\r
+ break;\r
+ case rDF:\r
+ StoreSize = 6;\r
+ break;\r
+ default:;\r
+ }\r
+}\r
+\r
+/* Now we loop thru looking for strings and numbers taking into account\r
+ the special case of DF which should be DWORD:WORD, and OFFSET\r
+ which will be a DWORD.\r
+*/\r
+\r
+while (1) {\r
+ if (fMoreStorage) {\r
+ i = Token;\r
+ fMoreStorage = 0;\r
+ }\r
+ else i = Parse();\r
+\r
+ switch(i) {\r
+ case STRING:\r
+ fComma=0;\r
+ if (StoreSize==1) {\r
+ for(j=0; j<CBString; j++) {\r
+ if (fListA) {\r
+ put_hexb(TString[j], lst_fh);\r
+ Column += 2;\r
+ Column += fprintf(lst_fh, " ");\r
+ if (Column > 51) {\r
+ fprintf(lst_fh, "\r\n ");\r
+ Column=16;\r
+ }\r
+ }\r
+ OutByte(TString[j]);\r
+ }\r
+ }\r
+ else {\r
+ line_error(46);\r
+ return;\r
+ }\r
+ break;\r
+ case rOFFSET:\r
+ if (StoreSize != 4) {\r
+ line_error(50);\r
+ return;\r
+ }\r
+ /* fall thru to evaluate & store value */\r
+ case NUMBER:\r
+ case DOLLAR: /* These should all evaluate to a number. */\r
+ case OPENRND: /* If it's SYMOFF, we do a fixup or Forward Ref */\r
+ case MINUS:\r
+ case SYMBOL:\r
+ case LSYMBOL:\r
+ case UNKSYM:\r
+ fComma=0;\r
+ if (!(Expression())) /* 0 means error was emmited. */\r
+ return;\r
+\r
+ symtype = 0; /* default to no symbol type */\r
+ nExtRef = 0; /* default to no external ref */\r
+\r
+ if ((Token==SYMOFF) || (Token==NUMOFF))\r
+ {\r
+ if (ExpType == 1) /* Local */\r
+ symtype = lst[iExpSym].Type;\r
+ else if (ExpType == 2) { /* global */\r
+ symtype = gst[iExpSym].Type;\r
+ if (gst[iExpSym].Type & tEXTRN)\r
+ nExtRef = iExpSym;\r
+ }\r
+ }\r
+\r
+ if (!fDUP) {\r
+ NSave = TNumber;\r
+ TSave = Token;\r
+ if (Parse() == rDUP)\r
+ {\r
+ nDUP = NSave;\r
+ fDUP = 1;\r
+ Parse();\r
+ if (Token == OPENRND) {\r
+ if (!(Expression())) /* 0 means error was emitted.*/\r
+ return;\r
+ }\r
+ else\r
+ line_error(47);\r
+ /* TNumber now has (VALUE) from DUP */\r
+ }\r
+ else {\r
+ ReturnToken();\r
+ TNumber = NSave;\r
+ Token = TSave;\r
+ }\r
+ }\r
+\r
+ if (StoreSize==6)\r
+ {\r
+ if (fColon) {\r
+ fColon=0; /* reset it */\r
+ if (fListA) {\r
+ sword = TNumber;\r
+ Column += 4;\r
+ put_hexw(sword, lst_fh);\r
+ Column += fprintf(lst_fh, " ");\r
+ }\r
+ OutWord(TNumber);\r
+ }\r
+ else {\r
+ fExpectColon = 1;\r
+ if (fListA) {\r
+ Column += 8;\r
+ put_hexd(TNumber, lst_fh);\r
+ Column += fprintf(lst_fh, " ");\r
+ }\r
+ OutDWord(TNumber);\r
+ }\r
+ }\r
+ else if (StoreSize==4) {\r
+ if (fDUP)\r
+ {\r
+ if (fListA) {\r
+ if ((Token == SYMOFF) || (Token == NUMOFF))\r
+ Column += fprintf(lst_fh, "%08lX * (%08lXr)",nDUP,TNumber);\r
+ else\r
+ Column += fprintf(lst_fh, "%08lX * (%08lX)",nDUP,TNumber);\r
+ }\r
+ while (nDUP--)\r
+ {\r
+ if ((Token==SYMOFF) || (Token==NUMOFF))\r
+ {\r
+ if (fDataSeg) { /* Data Seg */\r
+ if (nExtRef)\r
+ ExtRef(DSEGREF, iExpSym);\r
+ else if (!symtype)\r
+ ForRef(DSEGREF, oNextData);\r
+ else if (symtype & CLABEL)\r
+ FixUp(DCFIXTAG, oNextData, 0);\r
+ else if (symtype & DLABEL)\r
+ FixUp(DDFIXTAG, oNextData, 0);\r
+ }\r
+ else { /* Code Seg */\r
+ if (nExtRef)\r
+ ExtRef(CSEGREF, iExpSym);\r
+ if (!symtype)\r
+ ForRef(CSEGREF, oNextCode);\r
+ else if (symtype & CLABEL)\r
+ FixUp(CCFIXTAG, oNextCode, 0);\r
+ else if (symtype & DLABEL)\r
+ FixUp(CDFIXTAG, oNextCode, 0);\r
+ }\r
+ }\r
+ OutDWord(TNumber);\r
+ }\r
+ }\r
+ else {\r
+ if (fListA)\r
+ {\r
+ if ((Token == SYMOFF) || (Token == NUMOFF))\r
+ Column += fprintf(lst_fh, " %08lXr", TNumber);\r
+ else\r
+ Column += fprintf(lst_fh, " %08lX", TNumber);\r
+ }\r
+\r
+ /* Fixup & Forref here! */\r
+ if ((Token==SYMOFF) || (Token==NUMOFF))\r
+ {\r
+ if (fDataSeg)\r
+ { /* Data Seg */\r
+ if (nExtRef)\r
+ ExtRef(DSEGREF, iExpSym);\r
+ else if (!symtype)\r
+ ForRef(DSEGREF, oNextData);\r
+ else if (symtype & CLABEL)\r
+ FixUp(DCFIXTAG, oNextData, 0);\r
+ else if (symtype & DLABEL)\r
+ FixUp(DDFIXTAG, oNextData, 0);\r
+ }\r
+ else\r
+ { /* Code Seg */\r
+ if (nExtRef)\r
+ ExtRef(CSEGREF, iExpSym);\r
+ else if (!symtype)\r
+ ForRef(CSEGREF, oNextCode);\r
+ else if (symtype & CLABEL)\r
+ FixUp(CCFIXTAG, oNextCode, 0);\r
+ else if (symtype & DLABEL)\r
+ FixUp(CDFIXTAG, oNextCode, 0);\r
+ }\r
+ }\r
+ OutDWord(TNumber);\r
+ }\r
+ }\r
+ else if (StoreSize==2) {\r
+ if (fDUP) {\r
+ if (fListA)\r
+ Column += fprintf(lst_fh, "%08lX * (%04lX) ",nDUP,TNumber);\r
+ while (nDUP--)\r
+ OutWord(TNumber);\r
+ }\r
+ else {\r
+ if (fListA)\r
+ Column += fprintf(lst_fh, "%04lX ", TNumber);\r
+ OutWord(TNumber);\r
+ }\r
+ }\r
+ else {\r
+ if (fDUP) {\r
+ if (fListA)\r
+ Column += fprintf(lst_fh, "%08lX * (%02lX) ",nDUP,TNumber);\r
+ while (nDUP--)\r
+ OutByte(TNumber);\r
+ }\r
+ else {\r
+ if (fListA)\r
+ Column += fprintf(lst_fh, "%02lX ", TNumber);\r
+ OutByte(TNumber);\r
+ }\r
+ }\r
+ break;\r
+ case COMMA: /* Just eat the comma */\r
+ if (fComma) {\r
+ line_error(48);\r
+ return;\r
+ }\r
+ fComma = 1;\r
+ break;\r
+ case COLON:\r
+ fComma=0;\r
+ if ((StoreSize == 6) && (fExpectColon)) {\r
+ fColon = 1;\r
+ fExpectColon = 0;\r
+ }\r
+ else {\r
+ line_error(49);\r
+ return;\r
+ }\r
+ break;\r
+ case ZERO:\r
+ if (fComma) fMoreStorage = 1;\r
+ return;\r
+ default: {\r
+ line_error(51);\r
+ fMoreStorage = 0;\r
+ return;\r
+ }\r
+ }\r
+}\r
+}\r
+\r
+/********************************************\r
+ Add new GLOBAL symbol to table (TString).\r
+ Then parse again to hand off to\r
+ proper function. This stores all\r
+ Symbols UPPER case.\r
+*********************************************/\r
+void NewSymbol()\r
+{\r
+S16 i;\r
+S8 fColon, fStorage;\r
+\r
+ if ((pSymNext + CBString) >= (pSymBuf + SYMBUFMAX))\r
+ fatal_error("Symbol buffer overflow...");\r
+ if (iSymNext >= SYMSMAX)\r
+ fatal_error("Symbol table overflow...");\r
+\r
+ strncpy(pSymNext, TString, CBString);\r
+ gst[iSymNext].Size = CBString;\r
+ gst[iSymNext].Type = 0; /* initialize type */\r
+ gst[iSymNext].Ptr = pSymNext;\r
+ gst[iSymNext].Line = lineno[level];\r
+ gst[iSymNext].Offs = 0;\r
+\r
+ /* All declarations that reach NewSymbol are either at\r
+ level 0 or defined as PUBLIC or EXTERN. */\r
+\r
+ if (fExtern)\r
+ gst[iSymNext].Type |= tEXTRN;\r
+ else\r
+ gst[iSymNext].Type |= tPUBLIC;\r
+\r
+ if (fFarLabel) gst[iSymNext].Type |= tFAR;\r
+\r
+ if (fDataSeg) {\r
+ if (!fExtern)\r
+ gst[iSymNext].Offs = oNextData;\r
+ gst[iSymNext].Type |= DLABEL;\r
+ }\r
+ else {\r
+ if (!fExtern)\r
+ gst[iSymNext].Offs = oNextCode;\r
+ gst[iSymNext].Type |= CLABEL;\r
+ }\r
+\r
+ /* update for next symbol */\r
+ pSymNext += CBString;\r
+ iSymNext++;\r
+\r
+\r
+ /* Now, parse again and hand off. We have just added a symbol\r
+ so expect to see an EQU, COLON or Storage statement.\r
+ If we don't see one of these it's an error unless it's an extern.\r
+ If we see a COLON we parse again and expect an instruction or EOL!\r
+ */\r
+\r
+ fStorage = 0;\r
+ fColon=0;\r
+ i = Parse();\r
+\r
+ if (i == COLON) {\r
+ fColon = 1;\r
+ if (fDataSeg) {\r
+ line_error(49);\r
+ return;\r
+ }\r
+ i = Parse();\r
+ }\r
+\r
+ switch(i) { /* parse returns Token */\r
+ case INSTRU:\r
+ if (fDataSeg) {\r
+ line_error(41);\r
+ return;\r
+ }\r
+ if (!fColon) {\r
+ line_error(54);\r
+ return;\r
+ }\r
+ Instruction();\r
+ break;\r
+ case rDB:\r
+ gst[iSymNext-1].Type |= sBYTE; /* type */\r
+ fStorage = 1;\r
+ break;\r
+ case rDW:\r
+ gst[iSymNext-1].Type |= sWORD; /* type */\r
+ fStorage = 1;\r
+ break;\r
+ case rDD:\r
+ gst[iSymNext-1].Type |= sDWORD; /* type */\r
+ fStorage = 1;\r
+ break;\r
+ case rDF:\r
+ if ((!fDataSeg) && (!fColon)) {\r
+ line_error(54);\r
+ return;\r
+ }\r
+ gst[iSymNext-1].Type |= sFWORD; /* type */\r
+ fStorage = 1;\r
+ break;\r
+ case rEQU:\r
+ line_error(55);\r
+ /* AddMacro(); */\r
+ break;\r
+ case COLON:\r
+ if (fExtern)\r
+ return;\r
+ case ZERO:\r
+ if ((fDataSeg) && (!fExtern))\r
+ line_error(56);\r
+ break;\r
+ default:\r
+ if (fDataSeg)\r
+ line_error(56);\r
+ }\r
+\r
+ if (gst[iSymNext-1].Type & tEXTRN)\r
+ fStorage = 0;\r
+\r
+ if (fStorage)\r
+ Storage();\r
+}\r
+\r
+/********************************************\r
+ This changes an EXTRN entry in the gst to\r
+ a PUBLIC once we find it. This checks to\r
+ make sure the extern declaration was the\r
+ same type as this public.\r
+*********************************************/\r
+\r
+void MakePublic(void)\r
+{\r
+S16 i;\r
+S8 fColon, fStorage;\r
+\r
+ if (gst[TSymnum].Type & tPUBLIC) {\r
+ line_error(64);\r
+ return;\r
+ }\r
+\r
+ if ((fDataSeg) && (!(gst[TSymnum].Type & DLABEL))) {\r
+ line_error(69);\r
+ return;\r
+ }\r
+\r
+ if ((!fDataSeg) && (!(gst[TSymnum].Type & CLABEL))) {\r
+ line_error(69);\r
+ return;\r
+ }\r
+\r
+ gst[TSymnum].Type |= tPUBLIC; /* Turn ON Public */\r
+ gst[TSymnum].Type &= ~tEXTRN; /* Turn off EXTERN */\r
+\r
+ if (fDataSeg)\r
+ gst[TSymnum].Offs = oNextData;\r
+ else\r
+ gst[TSymnum].Offs = oNextCode;\r
+\r
+ /* Now, parse again and hand off. We have just added a symbol\r
+ so expect to see an EQU, COLON or Storage statement.\r
+ If we don't see one of these it's an error unless it's an extern.\r
+ If we see a COLON we parse again and expect an instruction or EOL!\r
+ */\r
+\r
+fStorage = 0;\r
+fColon=0;\r
+i = Parse();\r
+\r
+if (i == COLON) {\r
+ fColon = 1;\r
+ if (fDataSeg) {\r
+ line_error(49);\r
+ return;\r
+ }\r
+ i = Parse();\r
+}\r
+\r
+switch(i) { /* parse returns Token */\r
+ case INSTRU:\r
+ if (fDataSeg) {\r
+ line_error(41);\r
+ return;\r
+ }\r
+ if (!fColon) {\r
+ line_error(54);\r
+ return;\r
+ }\r
+ Instruction();\r
+ break;\r
+ case rDB:\r
+ gst[TSymnum].Type |= sBYTE; /* type */\r
+ fStorage = 1;\r
+ break;\r
+ case rDW:\r
+ gst[TSymnum].Type |= sWORD; /* type */\r
+ fStorage = 1;\r
+ break;\r
+ case rDD:\r
+ gst[TSymnum].Type |= sDWORD; /* type */\r
+ fStorage = 1;\r
+ break;\r
+ case rDF:\r
+ if ((!fDataSeg) && (!fColon)) {\r
+ line_error(54);\r
+ return;\r
+ }\r
+ gst[TSymnum].Type |= sFWORD; /* type */\r
+ fStorage = 1;\r
+ break;\r
+ case rEQU:\r
+ line_error(55);\r
+ break;\r
+ case COLON:\r
+ return;\r
+ default:\r
+ if (fDataSeg)\r
+ line_error(56);\r
+ }\r
+\r
+if (fStorage)\r
+ Storage();\r
+\r
+}\r
+\r
+\r
+/********************************************\r
+ This checks to ensure multiple externs are\r
+ the same type when we run across them, and\r
+ also that an extern is the same type if\r
+ the public is already declared.\r
+*********************************************/\r
+void CheckExtern(void)\r
+{\r
+ /* Check to make sure new extern and symbol are same type */\r
+\r
+ if ((fDataSeg) && (!(gst[TSymnum].Type & DLABEL))) {\r
+ line_error(69);\r
+ return;\r
+ }\r
+\r
+ if ((!fDataSeg) && (!(gst[TSymnum].Type & CLABEL))) {\r
+ line_error(69);\r
+ return;\r
+ }\r
+}\r
+\r
+\r
+/********************************************\r
+ Add new LOCAL symbol to table (TString).\r
+ Then parse again to hand off to\r
+ proper function. This stores all\r
+ Symbols UPPER case.\r
+*********************************************/\r
+void NewLSymbol(void)\r
+{\r
+S16 i;\r
+S8 fColon, fStorage;\r
+\r
+if ((pLSymNext + CBString) >= (pLSymBuf + LSYMBUFMAX))\r
+ fatal_error("Local symbol buffer overflow...");\r
+if (iLSymNext >= LSYMSMAX)\r
+ fatal_error("Local symbol table overflow...");\r
+\r
+strncpy(pLSymNext, TString, CBString);\r
+lst[iLSymNext].Size = CBString;\r
+lst[iLSymNext].Type = 0; /* initialize type */\r
+lst[iLSymNext].Ptr = pLSymNext;\r
+lst[iLSymNext].Line = lineno[level];\r
+\r
+if (fDataSeg) {\r
+ lst[iLSymNext].Offs = oNextData;\r
+ lst[iLSymNext].Type |= DLABEL;\r
+ }\r
+else {\r
+ lst[iLSymNext].Offs = oNextCode;\r
+ lst[iLSymNext].Type |= CLABEL;\r
+ }\r
+\r
+/* update for next symbol */\r
+pLSymNext += CBString;\r
+iLSymNext++;\r
+\r
+/* Now, parse again and hand off. We have just added a symbol\r
+so expect to see an EQU, COLON or Storage statement.\r
+If we don't see one of these it's an error!\r
+If we see a COLON we parse again and expect an instruction or EOL!\r
+ */\r
+\r
+fStorage = 0;\r
+fColon=0;\r
+i = Parse();\r
+\r
+if (i == COLON) {\r
+ fColon = 1;\r
+ if (fDataSeg) {\r
+ line_error(49);\r
+ return;\r
+ }\r
+ i = Parse();\r
+}\r
+\r
+switch(i) { /* parse returns Token */\r
+ case INSTRU:\r
+ if (fDataSeg) {\r
+ line_error(41);\r
+ return;\r
+ }\r
+ if (!fColon) {\r
+ line_error(54);\r
+ return;\r
+ }\r
+ Instruction();\r
+ break;\r
+ case rDB:\r
+ lst[iLSymNext-1].Type |= sBYTE; /* type */\r
+ fStorage = 1;\r
+ break;\r
+ case rDW:\r
+ lst[iLSymNext-1].Type |= sWORD; /* type */\r
+ fStorage = 1;\r
+ break;\r
+ case rDD:\r
+ lst[iLSymNext-1].Type |= sDWORD; /* type */\r
+ fStorage = 1;\r
+ break;\r
+ case rDF:\r
+ if ((!fDataSeg) && (!fColon)) {\r
+ line_error(54);\r
+ return;\r
+ }\r
+ lst[iLSymNext-1].Type |= sFWORD; /* type */\r
+ fStorage = 1;\r
+ break;\r
+ case rEQU:\r
+ AddMacro();\r
+ break;\r
+ case COLON:\r
+ return;\r
+ default:\r
+ if (fDataSeg)\r
+ line_error(56);\r
+ }\r
+\r
+if (lst[iLSymNext-1].Type & tEXTRN)\r
+ fStorage = 0;\r
+\r
+if (fStorage)\r
+ Storage();\r
+\r
+}\r
+\r
+/*****************************************\r
+ After we transition from level 1 back to\r
+ level 0 we go back to the point in the\r
+ code or data file where we began writing this\r
+ section and resolve all forward code\r
+ and local data references. These will be\r
+ referenced in the module we just finished.\r
+ ******************************************/\r
+\r
+void Resolve(void)\r
+{\r
+int i, isym;\r
+S32 Relative;\r
+S32 Partial;\r
+S32 AddFix;\r
+\r
+ i = 0;\r
+\r
+ while (i < iRefNext) /* While there are forward references */\r
+ {\r
+ if (pfrt[i].Type == DSEGREF) /* Ref is in DSEG */\r
+ {\r
+ fseek(ds_fh, (pfrt[i].Offs - DataOffset) , SEEK_SET);\r
+ fread(&Partial, 4, 1, ds_fh);\r
+ fseek(ds_fh, (pfrt[i].Offs - DataOffset) , SEEK_SET);\r
+ AddFix = pfrt[i].Offs - DataOffset;\r
+ }\r
+ else /* Ref is in CSEG */\r
+ {\r
+ fseek(cs_fh, (pfrt[i].Offs - CodeOffset) , SEEK_SET);\r
+\r
+ if (pfrt[i].Type == CSEGREF) /* IT'S ABSOLUTE! */\r
+ {\r
+ fread(&Partial, 4, 1, cs_fh);\r
+ fseek(cs_fh, (pfrt[i].Offs - CodeOffset) , SEEK_SET);\r
+ AddFix = pfrt[i].Offs - CodeOffset;\r
+ }\r
+ }\r
+ /* We are where we should write the reference\r
+ now we need to find it in the local symbol table\r
+ and calculate the proper offset. The calculation\r
+ is different for Relative and absolute references.\r
+ For Relative, we subtract the address where the correction\r
+ is going to be stored from the offset of reference.\r
+ For Absolute, we read what was already at the address\r
+ and add it to the offset of the referenced item.\r
+ Both of these are also adjusted for the Virtual segment offset.\r
+ */\r
+\r
+ /* Look in the Local Symbol table first! */\r
+\r
+ isym = findLsymbol(pfrt[i].Ptr, pfrt[i].NameSz);\r
+\r
+ if (isym) /* we found it! */\r
+ {\r
+ if (pfrt[i].Type == CCR8REF) /* 8 bit relative */\r
+ {\r
+ Relative = lst[isym].Offs - (pfrt[i].Offs - CodeOffset + 1);\r
+ OutByteCS(Relative);\r
+ }\r
+ else if (pfrt[i].Type == CCR32REF) /* 32 bit relative */\r
+ {\r
+ /* Fixed to make relatives ok in Virtual Segs */\r
+\r
+ Relative = (lst[isym].Offs - CodeOffset) -\r
+ (pfrt[i].Offs - CodeOffset + 4);\r
+ OutDWordCS(Relative);\r
+ }\r
+ else if (pfrt[i].Type == CSEGREF) /* 32 bit absolute */\r
+ {\r
+ Partial += lst[isym].Offs;\r
+\r
+ if (lst[isym].Type & CLABEL)\r
+ FixUp(CCFIXTAG, AddFix, 0);\r
+ else if (lst[isym].Type & DLABEL)\r
+ FixUp(CDFIXTAG, AddFix, 0);\r
+\r
+ OutDWordCS(Partial);\r
+ }\r
+ else if (pfrt[i].Type == DSEGREF)\r
+ {\r
+ Partial += lst[isym].Offs; /* RAB was + DataOffset */\r
+\r
+ if (lst[isym].Type & CLABEL)\r
+ FixUp(DCFIXTAG, AddFix, 0);\r
+ else if (lst[isym].Type & DLABEL)\r
+ FixUp(DDFIXTAG, AddFix, 0);\r
+\r
+ OutDWordDS(Partial);\r
+ }\r
+ }\r
+ else /* Look in Global table */\r
+ {\r
+\r
+ isym = findGsymbol(pfrt[i].Ptr, pfrt[i].NameSz);\r
+\r
+ if (isym)\r
+\r
+ { /* we found it! */\r
+\r
+\r
+ if (pfrt[i].Type == CCR8REF) { /* 8 bit relative */\r
+ Relative = gst[isym].Offs - (pfrt[i].Offs - CodeOffset + 1);\r
+ OutByteCS(Relative);\r
+ }\r
+ else if (pfrt[i].Type == CCR32REF) { /* 32 bit relative */\r
+ Relative = gst[isym].Offs - (pfrt[i].Offs - CodeOffset + 4);\r
+ OutDWordCS(Relative);\r
+ }\r
+ else if (pfrt[i].Type == CSEGREF) {\r
+ Partial += gst[isym].Offs;\r
+\r
+ if (gst[isym].Type & CLABEL)\r
+ FixUp(CCFIXTAG, AddFix, 0);\r
+ else if (gst[isym].Type & DLABEL)\r
+ FixUp(CDFIXTAG, AddFix, 0);\r
+\r
+ OutDWordCS(Partial);\r
+ }\r
+ else if (pfrt[i].Type == DSEGREF)\r
+ {\r
+ Partial += gst[isym].Offs;\r
+\r
+ if (gst[isym].Type & CLABEL)\r
+ FixUp(DCFIXTAG, AddFix, 0);\r
+ else if (gst[isym].Type & DLABEL)\r
+ FixUp(DDFIXTAG, AddFix, 0);\r
+\r
+ OutDWordDS(Partial);\r
+ }\r
+ }\r
+ else\r
+ prev_error("Unresolved symbol in current module", pfrt[i].Line);\r
+ }\r
+ i++;\r
+ }\r
+\r
+ fseek(cs_fh, 0L, SEEK_END); /* Get back to the end! */\r
+ fseek(ds_fh, 0L, SEEK_END);\r
+\r
+}\r
+\r
+/*****************************************\r
+ When we have processed all the source\r
+ we call this to resolve ALL externals.\r
+ ******************************************/\r
+\r
+void ResolveExt(void)\r
+{\r
+int i, isym;\r
+S32 Relative;\r
+S32 Partial;\r
+S32 AddFix;\r
+char name[31];\r
+\r
+i = 0;\r
+Partial = 0;\r
+Relative = 0;\r
+AddFix = 0;\r
+\r
+while (i < iERefNext) { /* While there are unresolved externals */\r
+\r
+ /* See if ref is in GST as PUBLIC */\r
+\r
+ isym = ert[i].iSym;\r
+\r
+ if (gst[isym].Type & tPUBLIC) {\r
+\r
+ if (ert[i].Type == DSEGREF) { /* Ref is in DSEG */\r
+\r
+ fseek(ds_fh, (ert[i].Offs - DataOffset) , SEEK_SET);\r
+ fread(&Partial, 4, 1, ds_fh);\r
+ fseek(ds_fh, (ert[i].Offs - DataOffset) , SEEK_SET);\r
+ AddFix = ert[i].Offs - DataOffset;\r
+ }\r
+ else { /* Ref is in CSEG */\r
+\r
+ fseek(cs_fh, (ert[i].Offs - CodeOffset) , SEEK_SET);\r
+\r
+ if (ert[i].Type == CSEGREF) { /* and IT'S ABSOLUTE! */\r
+ fread(&Partial, 4, 1, cs_fh);\r
+ fseek(cs_fh, (ert[i].Offs - CodeOffset) , SEEK_SET);\r
+ AddFix = ert[i].Offs - CodeOffset;\r
+ }\r
+ }\r
+ /* We are where we should write the reference\r
+ now we need to use the index in the external ref\r
+ table to see if it has been defined PUBLIC.\r
+ If so, we resolve it, else we error out.\r
+ To resolve it, the calculation is different for Relative\r
+ and absolute references.\r
+ For Relative, we subtract the address where the correction\r
+ is going to be stored from the offset of reference.\r
+ For Absolute, we read what was already at the address\r
+ and add it to the offset of the referenced item.\r
+ Both of these are also adjusted for the Virtual segment offset.\r
+ */\r
+\r
+ if (ert[i].Type == CCR32REF) { /* 32 bit relative */\r
+\r
+ /* Fixed to make relatives ok in Virtual Segs */\r
+\r
+ Relative = (gst[isym].Offs - CodeOffset) -\r
+ (ert[i].Offs - CodeOffset + 4);\r
+ OutDWordCS(Relative);\r
+ }\r
+ else if (ert[i].Type == CSEGREF) {\r
+ Partial += gst[isym].Offs;\r
+\r
+ if (gst[isym].Type & DLABEL)\r
+ FixUp(CDFIXTAG, AddFix, 0);\r
+ else if (gst[isym].Type & CLABEL)\r
+ FixUp(CCFIXTAG, AddFix, 0);\r
+\r
+ OutDWordCS(Partial);\r
+ }\r
+ else if (ert[i].Type == DSEGREF) {\r
+ Partial += gst[isym].Offs;\r
+\r
+ if (gst[isym].Type & CLABEL)\r
+ FixUp(DCFIXTAG, AddFix, 0);\r
+ else if (gst[isym].Type & DLABEL)\r
+ FixUp(DDFIXTAG, AddFix, 0);\r
+\r
+ OutDWordDS(Partial);\r
+ }\r
+ }\r
+ else {\r
+ strncpy(name, gst[isym].Ptr, gst[isym].Size);\r
+ name[gst[isym].Size] = '\0';\r
+ fprintf(lst_fh, "Unresolved external: %s\n", name);\r
+ Column = 0;\r
+ ++error_count;\r
+ }\r
+i++;\r
+} /* while more Erefs */\r
+\r
+fseek(cs_fh, 0L, SEEK_END); /* Get back to the end! */\r
+fseek(ds_fh, 0L, SEEK_END);\r
+\r
+}\r
+\r
+/*****************************************\r
+ If there were no errors, and all looks\r
+ well, we build the run file. This consists\r
+ of building the required tags in order\r
+ and writing them to the file with the\r
+ data.\r
+******************************************/\r
+\r
+void BuildRunFile(void)\r
+{\r
+unsigned char b;\r
+int i;\r
+long sdata;\r
+\r
+ tag.id = IDTAG; /* File type */\r
+ tag.len = 1;\r
+ fwrite(&tag, 5, 1, run_fh); /* Write the tag record */\r
+ fwrite(&filetype, 1, 1, run_fh); /* Write the filetype */\r
+\r
+ /* Version tag goes here */\r
+ /* DatTime tag goes here */\r
+ /* Comment tag(s) goes here */\r
+\r
+ tag.id = SEGTAG; /* Initial Segment Sizes */\r
+ tag.len = 12;\r
+ fwrite(&tag, 5, 1, run_fh); /* Write the tag record */\r
+ fwrite(&StackTotal, 4, 1, run_fh); /* Write the Stacktotal */\r
+ sdata = oNextCode - CodeOffset; /* Size of CS.TMP */\r
+ fwrite(&sdata, 4, 1, run_fh); /* Write the Code Size */\r
+ sdata = oNextData - DataOffset; /* Size of DS.TMP */\r
+ fwrite(&sdata, 4, 1, run_fh); /* Write the Data Size */\r
+\r
+ printf("Stack Size: %ld\r\n", StackTotal);\r
+ printf("Code Size: %ld\r\n", oNextCode - CodeOffset);\r
+ printf("Data Size: %ld\r\n", oNextData - DataOffset);\r
+\r
+ tag.id = DOFFTAG; /* Assumed Data Offset */\r
+ tag.len = 4;\r
+ fwrite(&tag, 5, 1, run_fh); /* Write the tag record */\r
+ fwrite(&DataOffset, 4, 1, run_fh); /* Write the data */\r
+\r
+ tag.id = COFFTAG; /* Assumed Code Offset */\r
+ tag.len = 4;\r
+ fwrite(&tag, 5, 1, run_fh); /* Write the tag record */\r
+ fwrite(&CodeOffset, 4, 1, run_fh); /* Write the data */\r
+\r
+ tag.id = STRTTAG; /* Starting Address */\r
+ tag.len = 4;\r
+ fwrite(&tag, 5, 1, run_fh); /* Write the tag record */\r
+ fwrite(&StartAddr, 4, 1, run_fh); /* Write the data */\r
+\r
+ tag.id = CODETAG; /* Code Segment */\r
+ tag.len = oNextCode - CodeOffset; /* Size of CS.TMP */\r
+ fwrite(&tag, 5, 1, run_fh); /* Write the tag record */\r
+\r
+ fseek(cs_fh, 0L , SEEK_SET);\r
+ sdata = tag.len;\r
+ while (sdata > 0) {\r
+ i = fread(line_buf0, 1, 200, cs_fh);\r
+ sdata -= i;\r
+ if (!i) break;\r
+ fwrite(line_buf0, 1, i, run_fh);\r
+ }\r
+\r
+ tag.id = DATATAG; /* Data Segment */\r
+ tag.len = oNextData - DataOffset; /* Size of DS.TMP */\r
+ fwrite(&tag, 5, 1, run_fh); /* Write the tag record */\r
+\r
+ fseek(ds_fh, 0L , SEEK_SET);\r
+ sdata = tag.len;\r
+ while (sdata > 0) {\r
+ i = fread(line_buf0, 1, 200, ds_fh);\r
+ sdata -= i;\r
+ if (!i) break;\r
+ fwrite(line_buf0, 1, i, run_fh);\r
+ }\r
+\r
+ if (nCDFix) {\r
+ tag.id = CDFIXTAG; /* CSEG Data Fixups */\r
+ tag.len = nCDFix * 4; /* Count * 4 of Fixups */\r
+ fwrite(&tag, 5, 1, run_fh); /* Write the tag record */\r
+ i = iFUNext;\r
+ while (i--) { /* Write CD fixups */\r
+ if (pfut[i].type == CDFIXTAG)\r
+ fwrite(&pfut[i].Offs, 1, 4, run_fh);\r
+ }\r
+ }\r
+\r
+ if (nCCFix) {\r
+ tag.id = CCFIXTAG; /* CSEG Code Fixups */\r
+ tag.len = nCCFix * 4; /* Count * 4 of Fixups */\r
+ fwrite(&tag, 5, 1, run_fh); /* Write the tag record */\r
+ i = iFUNext;\r
+ while (i--) { /* Write CC fixups */\r
+ if (pfut[i].type == CCFIXTAG)\r
+ fwrite(&pfut[i].Offs, 1, 4, run_fh);\r
+ }\r
+ }\r
+\r
+ if (nDDFix) {\r
+ tag.id = DDFIXTAG; /* DESG Data Fixups */\r
+ tag.len = nDDFix * 4; /* Count * 4 of Fixups */\r
+ fwrite(&tag, 5, 1, run_fh); /* Write the tag record */\r
+ i = iFUNext;\r
+ while (i--) { /* Write DD fixups */\r
+ if (pfut[i].type == DDFIXTAG)\r
+ fwrite(&pfut[i].Offs, 1, 4, run_fh);\r
+ }\r
+ }\r
+\r
+ if (nDCFix) {\r
+ tag.id = DCFIXTAG; /* DESG Code Fixups */\r
+ tag.len = nDCFix * 4; /* Count * 4 of Fixups */\r
+ fwrite(&tag, 5, 1, run_fh); /* Write the tag record */\r
+ i = iFUNext;\r
+ while (i--) { /* Write DC fixups */\r
+ if (pfut[i].type == DCFIXTAG)\r
+ fwrite(&pfut[i].Offs, 1, 4, run_fh);\r
+ }\r
+ }\r
+\r
+ /* DLL Address fixup tag goes here */\r
+ /* DLL Public tag goes here */\r
+\r
+ tag.id = ENDTAG; /* End Tag */\r
+ tag.len = 4; /* Size of CS.TMP */\r
+ fwrite(&tag, 5, 1, run_fh); /* Write the tag record */\r
+ sdata = 0;\r
+ fwrite(&sdata, 4, 1, run_fh); /* Write the tag record */\r
+\r
+}\r
+\r
+\r
+/*****************************************\r
+ Reads a whole line into line buffer.\r
+******************************************/\r
+\r
+S16 readline(void)\r
+{\r
+U32 i;\r
+U8 *pLine;\r
+\r
+ if (!(fgets(line_ptr = line_buf0, 100, src_fh[level]))) {\r
+\r
+ if (level) { /* we are in a nested include */\r
+ fclose(src_fh[level]);\r
+ --level;\r
+ if (level==0) { /* back up one level */\r
+\r
+ /* Processes forward references from this module */\r
+ Resolve();\r
+\r
+ if (fSymDump) {\r
+ DumpLSymbols();\r
+ DumpFRT();\r
+ }\r
+\r
+ /* Clear local symbol, forward refs, & macro tables */\r
+\r
+ iLSymNext = 1; /* 1st entry. */\r
+ pLSymNext = pLSymBuf; /* beginning of buffer */\r
+\r
+ iRefNext = 0; /* 1st entry. */\r
+ pRefNext = pRefBuf; /* Allocate memory - Was RefBuf */\r
+\r
+ iMacNext = 0; /* 1st entry */\r
+ pMacNext = pMacBuf; /* Begining of buffer */\r
+\r
+\r
+ }\r
+ if (fListA)\r
+ fprintf(lst_fh, "\r\n ");\r
+ fprintf(lst_fh, "CONTINUING-> %s, Level:%d\r\n", srcname[level],level);\r
+ fprintf(lst_fh, "\r\n");\r
+\r
+ if (lineno[level]) --lineno[level];\r
+ fContinue = 1;\r
+ }\r
+ else { /* We are at the end of the ATF file */\r
+\r
+ /* Processes forward references from Level 0 */\r
+ Resolve();\r
+\r
+ if (fSymDump) {\r
+ DumpGSymbols();\r
+ DumpFRT();\r
+ }\r
+\r
+ if (!fStart)\r
+ line_error(12); /* Starting address not found */\r
+\r
+ if (!error_count)\r
+ ResolveExt();\r
+\r
+ printf("%d Errors\r\n%d Warnings\r\n", error_count, warn_count);\r
+\r
+ if (fListA | fListE)\r
+ fprintf(lst_fh,"%d Errors\r\n%d Warnings\r\n",\r
+ error_count,warn_count);\r
+\r
+ if (!error_count) {\r
+ printf("Building Run file...\n");\r
+ BuildRunFile();\r
+ printf("Done.\n");\r
+ }\r
+\r
+ fclose(lst_fh);\r
+ fclose(cs_fh);\r
+ fclose(ds_fh);\r
+ fclose(lst_fh);\r
+ fclose(src_fh[level]);\r
+ remove("CS.TMP");\r
+ remove("DS.TMP");\r
+ exit(1);\r
+ }\r
+ }\r
+\r
+ list_buf[0] = 0;\r
+ if (fListA) {\r
+ pLine = line_ptr;\r
+ i=0;\r
+ while (isspace(*pLine)) pLine++;\r
+ while ((*pLine) && (*pLine != ';') && (*pLine != 0x0A))\r
+ list_buf[i++] = *pLine++;\r
+ while ((i) && (list_buf[i-1] == ' ')) --i; /* eat trailing spaces */\r
+ list_buf[i] = 0; /* null terminate */\r
+ if (i) fLineIn = 1;\r
+ else fLineIn = 0;\r
+ }\r
+ ++lineno[level];\r
+ return(1);\r
+}\r
+\r
+\r
+/********************************************\r
+ Dispatch calls Parse from the beginning\r
+ of a line and calls the proper routine\r
+ based on what it finds (from Parse()).\r
+ Dispatch calls readline to get a new line\r
+ after each of the line-specific modules\r
+ gets done with it's line or lines(s).\r
+*********************************************/\r
+\r
+void Dispatch(void)\r
+{\r
+S16 i, j;\r
+S8 st[80];\r
+\r
+while (1) {\r
+ readline();\r
+\r
+ if (fContinue) { /* We have just returned from an include */\r
+ fContinue = 0; /* and must reread the line without processing */\r
+ continue;\r
+ }\r
+\r
+ if (lineno[level] == 1) {\r
+ if (fListA)\r
+ fprintf(lst_fh, "\r\n ");\r
+ fprintf(lst_fh, "PROCESSING-> %s, Level:%d\r\n", srcname[level], level);\r
+ }\r
+\r
+ if (fListA) {\r
+ Column = fprintf(lst_fh, "%06d ", lineno[level]);\r
+ }\r
+\r
+ fPublic = 0;\r
+ fExtern = 0;\r
+ fFarLabel = 0;\r
+\r
+ i = Parse();\r
+ if (fMoreStorage)\r
+ Storage();\r
+ else switch (i) {\r
+ case INSTRU:\r
+ if (fListA)\r
+ Column += fprintf(lst_fh, "%08lX ", *pNextAddr);\r
+ Instruction();\r
+ break;\r
+ case REGIST:\r
+ line_error(63);\r
+ break;\r
+ case SYMBOL:\r
+ line_error(64);\r
+ break;\r
+ case LSYMBOL:\r
+ line_error(65);\r
+ break;\r
+ case STRING:\r
+ case NUMBER:\r
+ line_error(66);\r
+ break;\r
+ case rPUBLIC:\r
+ fPublic = 1;\r
+ if (fListA)\r
+ Column += fprintf(lst_fh, "%08lX ", *pNextAddr);\r
+ j = Parse();\r
+ if (j==SYMBOL)\r
+ MakePublic();\r
+ else if (j==UNKSYM)\r
+ NewSymbol();\r
+ else\r
+ line_error(67);\r
+ break;\r
+ case rEXTRN:\r
+ fExtern = 1;\r
+ if (fListA)\r
+ Column += fprintf(lst_fh, "%08lX ", *pNextAddr);\r
+ j = Parse();\r
+ if (j==SYMBOL)\r
+ CheckExtern();\r
+ else if (j==UNKSYM)\r
+ NewSymbol();\r
+ else\r
+ line_error(67);\r
+ break;\r
+ case UNKSYM:\r
+ if (fListA)\r
+ Column += fprintf(lst_fh, "%08lX ", *pNextAddr);\r
+ if (level)\r
+ NewLSymbol();\r
+ else\r
+ NewSymbol();\r
+ break;\r
+ case DOT:\r
+ Command();\r
+ break;\r
+ case rDB:\r
+ case rDD:\r
+ case rDW:\r
+ case rDF:\r
+ if (fListA)\r
+ Column += fprintf(lst_fh, "%08lX ", *pNextAddr);\r
+ Storage();\r
+ break;\r
+ case ZERO:\r
+ break;\r
+ default:\r
+ line_error(68);\r
+ break;\r
+ }\r
+\r
+ if ((fLineIn) && (fListA)) {\r
+ while (Column < 53) Column += fprintf(lst_fh, " ");\r
+ fprintf(lst_fh, "%s", list_buf);\r
+ }\r
+ if (Column)\r
+ fprintf(lst_fh, "\r\n");\r
+\r
+ } /* while */\r
+}\r
+\r
+/*********************\r
+* Main program\r
+**********************/\r
+\r
+void main(S16 argc, S8 *argv[])\r
+{\r
+S8 *ptr, *pname;\r
+S16 i, j, fdone;\r
+\r
+ lst_fh = stdout; /* default the list file */\r
+\r
+ for(i=1; i < argc; ++i) {\r
+ ptr = argv[i];\r
+ if (*ptr == '/') {\r
+ ptr++;\r
+ switch(*ptr) {\r
+ case 'L' : /* List file ON */\r
+ case 'l' :\r
+ fListA = 1;\r
+ break;\r
+ case 'S' : /* Dump Symbols */\r
+ case 's' :\r
+ fSymDump = 1;\r
+ break;\r
+ case 'E' : /* List file ON for errors/warns only */\r
+ case 'e' :\r
+ fListE = 1;\r
+ break;\r
+ case 'D' : /* Process as DLL */\r
+ case 'd' :\r
+ filetype = 2;\r
+ break;\r
+ case 'V' : /* Process as Devive Driver */\r
+ case 'v' :\r
+ filetype = 3;\r
+ break;\r
+ default:\r
+ fatal_error("Invalid option\n");\r
+ break;\r
+ }\r
+ }\r
+ else {\r
+ if(!src_fh[0]) {\r
+ strncpy(srcname, argv[i], 39);\r
+ src_fh[0] = fopen(argv[i], "r");\r
+ }\r
+ else if(!run_fh) {\r
+ strncpy(runname, argv[i], 39);\r
+ if(!(run_fh = fopen(argv[i], "wb"))) {\r
+ fatal_error("Can't open RUN file\n");\r
+ }\r
+ }\r
+ else\r
+ fatal_error("Too many options\n"); /* Too many parameters */\r
+ }\r
+ }\r
+\r
+/* Input file not explicitly named errors out */\r
+ if(!src_fh[0]) {\r
+ printf("Usage: ATFfile [RunFile] /L /E /D /V\r\n");\r
+ printf("/L = Complete List file generated\r\n");\r
+ printf("/S = Include SYMBOLS (only in complete list file)\r\n");\r
+ printf("/E = List file for Errors/warnings only\r\n");\r
+ printf("/D = Process as Dynamic link library\r\n");\r
+ printf("/V = Process as deVice driver\r\n");\r
+ fatal_error("Can't open Template file\n"); /* Can't open ATF file */\r
+ }\r
+\r
+/* Output file not explicitly named defaults to Source.RUN */\r
+\r
+ if(!run_fh) { /* default asm name to SourceName.run */\r
+ strncpy(runname, srcname, 40);\r
+ pname=runname;\r
+ while ((*pname != '.') && (*pname!= '\0')) pname++;\r
+ *pname++ = '.';\r
+ if (filetype == 2) {\r
+ *pname++ = 'D';\r
+ *pname++ = 'L';\r
+ *pname++ = 'L';\r
+ }\r
+ else if (filetype == 3) {\r
+ *pname++ = 'D';\r
+ *pname++ = 'D';\r
+ *pname++ = 'R';\r
+ }\r
+ else {\r
+ filetype = 1;\r
+ *pname++ = 'R';\r
+ *pname++ = 'U';\r
+ *pname++ = 'N';\r
+ }\r
+ *pname = '\0';\r
+ if(!(run_fh = fopen(runname, "wb"))) {\r
+ fatal_error("Can't open OUTPUT file\n"); /* Can't open RUN file */\r
+ }\r
+ }\r
+\r
+/* List file named Source.LIS for fListA and fListE only. */\r
+\r
+ if (fListA | fListE) {\r
+ strncpy(lstname, srcname, 40);\r
+ pname=lstname;\r
+ while ((*pname != '.') && (*pname!= '\0')) pname++;\r
+ *pname++ = '.';\r
+ *pname++ = 'L';\r
+ *pname++ = 'I';\r
+ *pname++ = 'S';\r
+ *pname = '\0';\r
+ if(!(lst_fh = fopen(lstname, "w")))\r
+ fatal_error("Can't open list file (source.LIS)\n"); /* Can't open List file */\r
+ }\r
+ else\r
+ lst_fh = stdout;\r
+\r
+printf("DASM-DOS Ver 1.6 (c) R.A. Burgess 1992,1993,1994\r\n\r\n");\r
+\r
+if (fListA | fListE)\r
+ fprintf(lst_fh, "DASM-DOS Ver 1.6 (c) R.A. Burgess 1992, 1993, 1994\r\n\r\n");\r
+\r
+if (fListA)\r
+ fprintf(lst_fh,\r
+ "LINE OFFSET ACTION/DATA/CODE SOURCE\r\n\r\n");\r
+\r
+ pLSymBuf = malloc(LSYMBUFMAX);\r
+ if(!pLSymBuf)\r
+ fatal_error("Can't Allocate buffer 1\n");\r
+\r
+ pSymBuf = malloc(SYMBUFMAX);\r
+ if(!pSymBuf)\r
+ fatal_error("Can't Allocate buffer 2\n");\r
+\r
+ pMacBuf = malloc(MACBUFMAX);\r
+ if(!pMacBuf)\r
+ fatal_error("Can't Allocate buffer 3\n");\r
+\r
+ pRefBuf = malloc(FREFBUFMAX);\r
+ if(!pRefBuf)\r
+ fatal_error("Can't Allocate buffer 4\n");\r
+\r
+ pfrt = malloc(FREFTABMAX);\r
+ if(!pfrt)\r
+ fatal_error("Can't Allocate buffer 5\n");\r
+\r
+ pfut = malloc(FIXUPBUFMAX);\r
+ if(!pfut)\r
+ fatal_error("Can't Allocate buffer 6\n");\r
+\r
+pSymNext = pSymBuf; /* Allocate memory - Was SymBuf */\r
+pLSymNext = pLSymBuf; /* Allocate memory - Was LSymBuf */\r
+pMacNext = pMacBuf; /* Allocate memory - Was MacBuf */\r
+pRefNext = pRefBuf; /* Allocate memory - Was RefBuf */\r
+\r
+\r
+pNextAddr = &oNextData; /* default to DataSeg */\r
+\r
+if(!(cs_fh = fopen(csname, "wb+")))\r
+ fatal_error("Can't open CS temp file\n");\r
+\r
+if(!(ds_fh = fopen(dsname, "wb+")))\r
+ fatal_error("Can't open DS temp file\n");\r
+\r
+/* We now build a dynamic instruction lookup table which indexes\r
+the first entry of an instruction in the opcode array rgINS.\r
+This is done dynamically because we are still optimizing.\r
+*/\r
+\r
+/* i is the instruction we are indexing */\r
+/* j is the position in rgINS */\r
+\r
+for (i=1; i<ninst+1; i++) {\r
+ for (j=1; j<nrgINS; j++) {\r
+ if (rgINS[j][0] == i) {\r
+ rgInsLookUp[i] = j;\r
+ break;\r
+ }\r
+ }\r
+}\r
+\r
+Dispatch();\r
+\r
+}\r