From 562ad2bf1e836da09d3b2bc8ceffe3d21b7ca17e Mon Sep 17 00:00:00 2001 From: Richard Burgess <> Date: Thu, 9 Feb 1995 16:53:44 +0000 Subject: [PATCH] autocommit for files dated 1995-02-09 16:53:44 --- msamples/dasmm/dasm.c | 3609 +++++++++++++++++++++++++++++++++++++ msamples/dasmm/dasm.h | 1355 ++++++++++++++ msamples/dasmm/dasm.run | Bin 0 -> 148211 bytes msamples/dasmm/dasmdbg.c | 83 + msamples/dasmm/dasmq.c | 1574 ++++++++++++++++ msamples/dasmm/makeit.bat | 2 + msamples/dasmm/read.me | 13 + 7 files changed, 6636 insertions(+) create mode 100644 msamples/dasmm/dasm.c create mode 100644 msamples/dasmm/dasm.h create mode 100644 msamples/dasmm/dasm.run create mode 100644 msamples/dasmm/dasmdbg.c create mode 100644 msamples/dasmm/dasmq.c create mode 100644 msamples/dasmm/makeit.bat create mode 100644 msamples/dasmm/read.me diff --git a/msamples/dasmm/dasm.c b/msamples/dasmm/dasm.c new file mode 100644 index 0000000..6b05777 --- /dev/null +++ b/msamples/dasmm/dasm.c @@ -0,0 +1,3609 @@ +/* + * Assembler for MMURTL (MMURTL Version). + * + * Copyright 1991,1992,1993,1994,1995 R.A. Burgess + + Version 1.2 11/20/93 - major rewrite on instruction table + Version 1.3 8/28/94 - Clear macro buf on level 1 to 0 transition + Version 1.4 9/29/94 - Smashed bug in 66| prefix for string commands + Version 1.5 10/5/94 - Optimized a couple of commands and fixed + bug in ENTER X,X instruction. This version seems + really stable ("yeaaaaa Right," he says...) + Actually it is.... + 10/29/94 Fix problem with sign extending bytes on ADD + Version 1.6 12/31/94 - Removed temp files on succesful assemble + Version 1.7M 1/1/95 - V1.6 ported to MMURTL. Changed memory allocation + use AllocPage and also created internal buffers + instead of using tmp files. Also use an internal + read buffer of 4K to make better use of Readbytes(). + OutWord, OutDWord, and OutByte had to be renamed + so they would not conflict with MMURTL publics of + the same names. + + */ + +#define U32 unsigned long +#define S32 long +#define U16 unsigned int +#define S16 int +#define U8 unsigned char +#define S8 char + + +#include +#include +#include +#include + +#include "dasm.h" +#include "runfile.h" +#include "\OSSource\MMemory.h" +#include "\OSSource\MFiles.h" + +/* variables */ + +#define LEVELS 5 +U32 level = 0; /* current include level */ +U32 lineno[LEVELS]; /* line number being parsed */ +U8 fContinue = 0; /* True if just returned from include */ + +char srcname[LEVELS][40]; /* also active include filenames */ +char runname[40]; +char lstname[40]; + +/* File handles for all files */ + +FILE *src_fh[5] = {0,0,0,0,0}; /* Current source file */ +FILE *run_fh = 0; /* Current .RUN, .DLL, or .DDR (output) */ + +FILE *lst_fh = 0; /* List file */ +FILE *sym_fh = 0; /* Symbol file for debugger */ + +#define STMPBUFS 512000 + +U8 *pcsbuf, *pdsbuf; /* half meg allocated buffers for code & data */ +U32 ics, ids; /* current index into tmp code & data buffers */ + +U8 filetype = 1; /* 1 = RUN, 2 = DLL, 3 = DDR */ + +U8 fListA = 0; /* True if detailed list file */ +U8 fListE = 0; /* True if Error only list file */ +U8 fSymDump = 0; /* True if we add symbols to the list file */ +U8 Column = 0; /* where are we on the LIST line */ +U32 error_count = 0; +U32 warn_count = 0; + + /* Max input line is 132, but 200 allows plenty for macro subs */ +S8 line_buf0[200]; /* Two buffers are swapped during macro substitution */ +S8 line_buf1[200]; +S8 *line_ptr; /* pointer to next char on line */ + +S8 list_buf[200]; /* Used to hold line string for list file */ +S8 fLineIn =0; /* TRUE is list_buf has something to list */ + +S8 TString[133]; /* all parsed tokens are placed here in text form */ +S32 CBString; /* size of parsed token */ +S32 TSymnum; /* Symbol table entry number, else 0 */ +U32 TNumber; /* value of numeric token */ +S32 TInst; /* Instruction number, else 0 */ +S32 TReg; /* Register number, else 0 */ +S32 Token; /* Token type (also returned from parse) */ +S8 fPutBack = 0; /* TRUE (non=zero) if last token was not used */ + +S8 LTString[133]; /* Duplicates of Token storage for ReturnToken(); */ +S32 LCBString; +S32 LTSymnum; +U32 LTNumber; +S32 LTInst; +S32 LTReg; +S32 LToken; + +S8 UString[31]; /* Place to save unknown labels for Forward Reference */ +S32 UCBString; /* Size of Unknown label */ + +/* The two Symbol tables have 5 entries; Type, Size, Pointer to Name, + Segment Offset, and Line. + As each symbol is found, it's identifed by type, and the name + is moved to the packed symbol buffer. A pointer is added to the + table to point to the name in the buffer, while it's size, type, + segment offset, and line number are added to the table. + Macro names are also stored in the symbol table, but offset entry + for a macro indicates it's offset in the Macro buffer. +*/ + +/* Variables for symbol tables */ + +/* Global Symbol Table */ + +#define SYMSMAX 700 +#define SYMBUFMAX 16384 /* Avg of 10 byte per name, 700 Max */ + +struct symtab { + U32 Type; /* Token (e.g, CLabel) */ + U32 Line; /* Line symbol was declared on */ + U32 Size; /* Size of symbol name */ + S8 *Ptr; /* Pointer to name in packed buffer */ + U32 Offs; /* Offset in segment */ + }; + +struct symtab gst[SYMSMAX]; /* storage for the GST */ + +/* S8 SymBuf[SYMBUFMAX]; */ /* Where names are stored. Will be Alloced */ +S8 *pSymBuf; /* ptr to allocated buffer */ + +S8 *pSymNext; /* ptr to next new entry in symbol buffer */ +S32 iSymNext = 1; /* index to next new symbol table entry. */ + /* Starts at 1 - zero it reserved because */ + /* Parse returns 0 for EOL */ + +S8 fPublic = 0; +S8 fExtern = 0; +S8 fFarLabel = 0; + +/*********** Local Symbol Table *************/ + +/* This is cleared after each include file from level 1 is closed */ +/* Clearing means we reset *pLSymNext to begining of buffer */ +/* and reset iLSymNext to 1. This "hides" local symbols. */ + +#define LSYMSMAX 1800 +#define LSYMBUFMAX 32768 /* Avg of 7 bytes per name */ + +struct symtab lst[LSYMSMAX]; /* storage for the LST */ + +/* S8 LSymBuf[LSYMBUFMAX]; */ /* Where names are stored.*/ +S8 *pLSymBuf; /* for allocated buffer */ + +S8 *pLSymNext; /* ptr to next new entry in symbol buffer */ +S32 iLSymNext = 1; /* index to next new symbol table entry. */ + /* Starts at 1 - zero it reserved because */ + /* Parse returns 0 for EOL */ + +/************* Forward Ref Table *********************************/ +/* + Labels that are encountered as forward references are + stored in this table. When we run across a forward, we do + not know what segment they are refering to unless it is from + a jump, call, or loop instruction. We will NOT know for many + items until they are actually declared. After all the code + and data has been processed, we go through this table + and fix all the unknown references using the relative + The type of forward references are: + + 1) DSEG DWORD item refers to UNK item (?Seg MemRef) + 2) CSEG DWORD item refers to UNK item (?Seg MemRef) + 3) CSEG to CSEG relative 8 (Jump, Jc, or Loop) + 4) CSEG to CSEG relative 32 (Jump or Call) + + MOTE: If a calculation is made with the unknown reference, 0 + is used in the calculation. We ALWAYS ADD the value we stored + with what is found when the reference is resolved. + +*/ + +#define FREFTABMAX 32768 +#define FREFSMAX 32768/14 +#define FREFBUFMAX 16384 + +/* Types of forward references. */ + +#define DSEGREF 1 /* 32 bit Abs Ref in DSeg, to what is unknown! */ +#define CSEGREF 2 /* 32 bit Abs Ref in CSeg, to what is unknown! */ +#define CCR32REF 3 /* 32 bit Relative in CSeg */ +#define CCR8REF 4 /* 8 bit Relative in CSeg */ + +struct forreftab { + U8 Type; /* 1, 2, 3, or 4 */ + U8 NameSz; /* Size of ref name */ + U32 Line; /* Line reference was made on (for error if not found) */ + S8 *Ptr; /* Pointer to name in packed buffer */ + S32 Offs; /* Offset in segment were it should go */ + }; + +struct forreftab *pfrt; /* pointer to allocated table */ + +S8 *pRefBuf; +S8 *pRefNext; /* ptr to next new entry in symbol buffer */ +S32 iRefNext = 0; /* index to next new forward ref table entry. */ + +/************ External Reference table ************/ + +/* External definitions that are encountered in a module are + first entered in the Global Symbol Table (GST) as externals + if they haven't already been defined (public) by the module + that owns them. + When a reference is made to an external, we see if the public has + already been defined. If so, we resolve it immediately. If not, + we make an entry in the External Reference Table (ERT). The + entry has the following 4 pieces of information: + - Line where reference was made. + - Index to place holder entry in GST. + - Segment where reference was made (boolean - TRUE for code seg). + - Offset in that segment where the resolution will be made. + With this information we can reslove all the external references + before we write the code segment to the run file. +*/ + +#define EREFSMAX 400 + +struct extreftab { + U8 Type; /* Type of reference so we know how to apply it */ + U32 iSym; /* Index of gst entry. Hi bit set if CSeg ref */ + U32 Offs; /* Offset in segment were ref needs 32 bit fixing */ + }; + +struct extreftab ert[FREFSMAX]; + +S32 iERefNext = 0; /* index to next external ref table entry. */ + +U32 nExtRef; + +/*********** Fix Up Table *********************/ + +/* This table holds 6 types of fixups along with the offset + in the segment to be fixed up, and if applicable, an index + to the DLL public name in the GST (which should be defined + as EXTRNDLL): + - Fixup type + - Ref in CSEG to address in DSEG + - Ref in CSEG to address in CSEG + - Ref in DSEG to address in DSEG + - Ref in DSEG to address in CSEG + - CSEG DLL near 32 bit call used + - CSEG DLL near 32 bit call defined + - Offset of 32 bit reference to be resolved + - Index to DLL public name in GST (if applicable) + + With this information we can supply the loader with the TAG entries + in the RUN file needed to resolve them. Most of these entries will + be made as we parse the code, but many will also be added after + we fix the forward references because we won't know what segment + the reference is made to until then. +*/ + +#define FIXUPSMAX 32768/7 +#define FIXUPBUFMAX 32768 + +struct futab + { + U8 type; /* Type of fixup C0, C1, C2, C3, C5, or C8 */ + U32 Offs; /* Offset in segment for 32 bit fixup */ + U32 iSym; /* index of DLL entry in gst, else 0 */ + }; + +struct futab *pfut; /* pointer to allocated Fix Up Table */ + +S32 iFUNext = 0; /* index to next fix up table entry. */ + /* Starts at 0 */ + +U32 nCDFix = 0; +U32 nDDFix = 0; +U32 nDCFix = 0; +U32 nCCFix = 0; + +/********* Macro variables *******************/ + +#define MACSMAX 300 +#define MACBUFMAX 4096 + +S8 *rgMacPtr[MACSMAX]; /* pointer to simple macros */ +S8 *pMacBuf; +S8 *pMacNext; /* ptr to next new entry in macro buffer */ +S32 iMacNext = 0; /* index to next new symbol entry */ + +/* Variables for current segment address offset tracking */ + +S8 fStart = 0; /* True if they gave a start address */ +S32 StartAddr = 0; /* Filled in when .START is encountered */ +S32 oNextData = 0; /* Tracks current DSEG offset */ +S32 oNextCode = 0; /* Tracks current CSEG offset */ +S32 CodeOffset = 0; /* From Virtual Command */ +S32 DataOffset = 0; /* From Virtual Command */ +S32 *pNextAddr = 0; /* Points to current segment offset counter */ +S8 fDataSeg = 0; /* True if parsing DSEG, else parsing CSEG */ +S32 StackTotal = 0; /* Total Stack Specified in Code segs */ + +/****************************************************************** + Variables for RAW operands in an instruction. + These are used when we read in and separate each part of the + operands so it can be evaluated. +*/ + +S32 rgToken[3][20]; /* Raw tokens in the operand (as many as 20) */ +S32 rgVal[3][20]; /* value if token is number/displacement */ +S32 rgTID[3][20]; /* Register ID if token is a register */ +S32 rgTCnt[3]; /* total count of tokens in raw operand */ + +/****************************************************************** + These variables are filled in while parsing and evaluating + instructions that have been read in. + They have all the info needed to + encode the instruction into the object module and + produce FixUp Records if needed. +*/ + +/* These are used in the description of all OPERANDS for the current + instruction we are working on. +*/ +S32 rgOpType[3]; /* Operand type for compare to instruction */ +S32 rgOpReg[3]; /* If reg only, this which one */ +S8 OpSize[3]; /* Operand size for first two (fByte, fWord, fFar etc.) */ +S8 OpSizeA; /* Overall operand size for instruction */ +S8 OpPrefix; /* Bit set for a segment prefix (fESp etc.) */ +S32 iInstEntry; /* Which entry is it in rgINS */ +S32 CrntInst; /* instruction we are working on */ +S32 InstPfx; /* Special Insturction prefix for crnt inst */ +S32 nOperands; /* number of operands we found */ +S8 fForRef; /* Crnt inst makes a Forward Reference */ + +/* The following vars are used if we have a memory reference that is + encoded as part of the instruction. +*/ +S8 OpMType; /* Mem type (compared to rgM32). 0 if not mem type */ +S32 OpBase; /* Base register if fBase is true */ +S32 OpIndx; /* Index register if fIndx is true */ +S32 OpDisp; /* Displacement if fDisp8 or fDisp32 is TRUE */ +S32 iMemEntry; /* If mem operand, which entry in rgM32 */ + +/* The following are used if we have immediate values to be encoded as +part of the instruction. Immediates can also be addresses such as +those in Direct and Relative Jumps and Calls! +*/ +S32 OpImm; /* Immediate value if fOpImm is true */ +S8 fOpImm; /* If OpImm has a value */ +S32 OpImm2; /* Second Imm value for iSAD and other multi-Imm types */ +S8 fOpImm2; /* If OpImm2 has a value */ + +/* This is set for each type of fixup required after an instruction +line. Data fixups are done directly in the code that generates +storage in DSeg. */ + +U8 nFixUp; /* Fixup number (Cx) */ + +/*************************************************************************/ + +/* In the final stages of building an instruction, these contain the + fragment bytes of encoded instructions (along with flags for + optional parts used). +*/ + +U8 bOpc1; /* Zero if not used */ +U8 bOpc2; /* Always used */ +U8 bModRM; /* ModRM byte value if used */ +U8 bSIB; /* SIB value if used */ +S8 fModRM; /* True if bModRM is used */ +S8 fSIB; /* True if bSIB is used */ + +/*** These are used in the expression parser ******/ + +U8 ExpType; /* 0 = Forward, 1 = Local, 2 = Global, 3 = Current Addr */ +U8 ExpType0; +S32 nExpSyms; /* Used by the numeric expression evaluator */ +S32 iExpSym, iExpSym0; /* if a symbol value translates to a SYMOFF, + this holds the symbol table index. */ +S8 fOffset; /* True if derived from an Offset */ + +/* Variables for Storage allocation */ + + +S8 fMoreStorage = 0; /* True when storage continues to next line */ +S32 StoreSize = 0; + +/**** Variables for building the RUN File (DLL or Device Driver) ********/ + +/* Once we have the CS and DS tmp files run through to correct any external + variables or forward labels, we build the run file. This is done + by building the tag records, sending them followed by the proper data + for each one. +*/ + +struct tagtype tag; + + +/******************* END VARIABLES - BEGIN CODE ********************/ + +/* ANSI prototypes for all functions are in DProtos.h */ + +#include "DProtos.h" + + +/***************************************************************/ +/* Write a DWord to the current segment and update the counter */ +/***************************************************************/ + +void OutDWordX(unsigned long Data) +{ +unsigned char *pOut, b; +long i; + pOut = &Data; + if (fDataSeg) { + for (i=0; i<4; i++) { + b = *pOut++; + pdsbuf[ids++] = b; /* fputc(b , ds_fh); */ + } + oNextData+=4; + } + else { + for (i=0; i<4; i++) { + b = *pOut++; + pcsbuf[ics++] = b; /* fputc(b , cs_fh); */ + } + oNextCode+=4; + } +} + +/******************************************************************/ +/* Write a DWord to the code segment and DO NOT update counter */ +/******************************************************************/ + +void OutDWordCS(unsigned long Data) +{ +unsigned char *pOut, b; +long i; + pOut = &Data; + for (i=0; i<4; i++) { + b = *pOut++; + pcsbuf[ics++] = b; /* fputc(b , cs_fh); */ + } +} + +/******************************************************************/ +/* Read n bytes from the code segment */ +/******************************************************************/ + +void readCS(U8 *pDataRet, long cbData) +{ + while (cbData--) + *pDataRet++ = pcsbuf[ics++]; +} + + +/******************************************************************/ +/* Write n bytes to the code segment and DO NOT update counter */ +/******************************************************************/ + +void writeCS(U8 *pData, long cbData) +{ + while (cbData--) + pcsbuf[ics++] = *pData++; +} + + +/**************************************************************** + Set index into code buffer +*****************************************************************/ + +void seekCS(long offset) +{ + ics = offset; +} + + +/******************************************************************/ +/* Write a DWord to the current segment and DO NOT update counter */ +/******************************************************************/ + +void OutDWordDS(unsigned long Data) +{ +unsigned char *pOut, b; +long i; + pOut = &Data; + for (i=0; i<4; i++) { + b = *pOut++; + pdsbuf[ids++] = b; /* fputc(b , ds_fh); */ + } +} + +/******************************************************************/ +/* Read n bytes from the code segment */ +/******************************************************************/ + +void readDS(U8 *pDataRet, long cbData) +{ + while (cbData--) + *pDataRet++ = pdsbuf[ids++]; +} + +/******************************************************************/ +/* Write n bytes to the data segment and DO NOT update counter */ +/******************************************************************/ + +void writeDS(U8 *pData, long cbData) +{ + while (cbData--) + pdsbuf[ids++] = *pData++; +} + +/**************************************************************** + Set index into data buffer +*****************************************************************/ + +void seekDS(long offset) +{ + ids = offset; +} + +/**************************************************************/ +/* Write a Word to the current segment and update the counter */ +/**************************************************************/ + +void OutWordX(unsigned long Data) +{ +unsigned char *pOut, b; +long i; + pOut = &Data; + b = *pOut++; + if (fDataSeg) { + pdsbuf[ids++] = b; /* fputc(b , ds_fh); */ + b = *pOut; + pdsbuf[ids++] = b; /* fputc(b , ds_fh); */ + oNextData+=2; + } + else { + pcsbuf[ics++] = b; /* fputc(b , cs_fh); */ + b = *pOut; + pcsbuf[ics++] = b; /* fputc(b , cs_fh); */ + oNextCode+=2; + } +} + +/**************************************************************/ +/* Write a BYTE to the current segment and update the counter */ +/**************************************************************/ + +void OutByteX(unsigned char Data) +{ + if (fDataSeg) { + pdsbuf[ids++] = Data; /* fputc(Data , ds_fh); */ + oNextData++; + } + else { + pcsbuf[ics++] = Data; /* fputc(b , cs_fh); */ + oNextCode++; + } +} + +/*****************************************************************/ +/* Write a BYTE to the current segment and DO NOT update counter */ +/*****************************************************************/ + +void OutByteCS(unsigned long Data) +{ +char b; + b = Data; + pcsbuf[ics++] = b; /* fputc(b , cs_fh); */ +} + +/* All the "grunt work" functions are in dasmq.c */ + +#include "DASMq.c" + +/********************************************* +This searches the Reference table for the name +described by pb, cb. It only compares items that +are the same length (cb == TRefSize[x]). +It returns the number or 0 if not found. +**********************************************/ + +S32 findref(S8 *pb, S32 cb) /* pointer to, and size of string */ +{ +S32 i; +S8 name[132]; + +strncpy(name, pb, cb); /* move name local */ +name[cb] = 0; /* null terminate */ + +i = iRefNext; +while (i>0) { /* backwards through forward ref table */ + i--; + /* Only compare if same size */ + if (pfrt[i].NameSz == cb) { + if (strncmp(name, pfrt[i].Ptr, cb) == 0) return(i); + } +} +return(0); +} + + +/***************************************************** + Evaluates only single token operands and sets up + globals so EvalOper can finish the job. + The actual value or register is left in + rgToken[op][0], and the type is placed + in rgTempl[op][0] for a memory operand. +*****************************************************/ +S32 EvalOper1(S32 op) +{ +S32 i; +U32 symtype; + + /* Set up symtype up front in case it's needed */ + + if (ExpType == 1) /* Local */ + symtype = lst[iExpSym].Type; + else if (ExpType == 2) { /* global */ + if (gst[iExpSym].Type & tEXTRN) + nExtRef = iExpSym; + symtype = gst[iExpSym].Type; + } + else symtype = 0; + + switch (rgToken[op][0]) { + case REGIST: + if (is_r32(rgTID[op][0])) rgOpType[op] = r32; + else if (is_r16(rgTID[op][0])) rgOpType[op] = r16; + else if (is_r8(rgTID[op][0])) rgOpType[op] = r8; + else if (is_rCRG(rgTID[op][0])) rgOpType[op] = rCRG; + else if (is_rDRG(rgTID[op][0])) rgOpType[op] = rDRG; + else if (is_rTRG(rgTID[op][0])) rgOpType[op] = rTRG; + else if (is_rSEG(rgTID[op][0])) rgOpType[op] = rSEG; + rgOpReg[op] = rgTID[op][0]; + break; + case NUMBER: + if ((rgVal[op][0] >= -128) && (rgVal[op][0] <= 127)) + rgOpType[op] = val8; + else if ((rgVal[op][0] >= -32768) && (rgVal[op][0] <= 32767)) + rgOpType[op] = val16; + else rgOpType[op] = val32; + if (!fOpImm) { + OpImm = rgVal[op][0]; + fOpImm = 1; + } + else { + OpImm2 = rgVal[op][0]; + fOpImm2 = 1; + } + break; + case NUMOFF: /* OFFSET var name. IMMEDIATE VALUE. */ + OpSize[op] = fDWord; + rgOpType[op] = val32; + OpImm = rgVal[op][0]; + fOpImm = 1; + if (symtype & CLABEL) + nFixUp = CCFIXTAG; + else if (symtype & DLABEL) + nFixUp = CDFIXTAG; + if (!symtype) + fForRef = 1; + break; + case SYMOFF: /* Check for ALL jump, call & Loop instructions */ + + if (ExpType == 1) /* Local */ + symtype = lst[iExpSym].Type; + else if (ExpType == 2) { /* global */ + if (gst[iExpSym].Type & tEXTRN) + nExtRef = iExpSym; + symtype = gst[iExpSym].Type; + } + else /* Unknown - Forward */ + symtype = 0; + + if (((CrntInst >= xJA) && + (CrntInst <= xJZ)) || + (CrntInst == xCALL)) { + + if (OpSize[op] & fShort) + rgOpType[op] = rel8; + else + rgOpType[op] = relW; + OpImm = rgVal[op][0]; + fOpImm = 1; + } + + else if ((CrntInst >= xLOOP) && (CrntInst <= xLOOPZ)) { + rgOpType[op] = rel8; + OpImm = rgVal[op][0]; + fOpImm = 1; + } + else { + rgOpType[op] = mem; + OpMType |= fDisp32; + OpDisp = rgVal[op][0]; + if (symtype & CLABEL) + nFixUp = CCFIXTAG; + else if (symtype & DLABEL) + nFixUp = CDFIXTAG; + } + if (!symtype) + fForRef = 1; + break; + default: + line_error(15); + return(0); + } /* switch */ + +/* print_Oper(op); Testing only... */ + +return(1); +} + +/*********** EvalOper ******************************* + Evaluates the array of reserved words, registers, + numbers, etc. that should make up an operand. + For single token operands it's easy! BUT for memory + operands it gets a little more complicated. + For memory operands we look for key sequences of + tokens that make up the "effective address" as + described in the Intel documentation, then see if + we have all the pieces to make one (EA). + This returns 1 if we can classify the operand and + there were no errors. The type of operand we find + (e.g., r8, r16, r32, val8, val16, val32, mem, + relW, etc.) is placed in rgOpType[op]. + This calls EvalOper1() to handle single token + oprerands and evaluates multiple token operands + internally. The reason we break single token operands + out in a separate call is for speed and clarity + of the code. + Special handling is required for for JMP, Jcond, + and CALL instructions because they may be using + a forward reference not yet defined. This is the + only case where such a reference is allowed. +*****************************************************/ + +S32 EvalOper(S32 op) +{ +S32 i; +S8 fDone, fOpenSQ, fError; +U32 symtype; +/* +These are the Raw operands: +S32 rgToken[3][20]; Raw tokens in the operand +S32 rgVal[3][20]; value if token is number/displacement +S32 rgTID[3][20]; Register ID if token is a register +S32 rgTCnt[3]; total count of tokens in raw operand + + This is what is produced: +*/ + +rgOpType[op] = 0; /* int - Operand type for compare to instruction */ +rgOpReg[op] = 0; /* If reg only, this which one */ + +i = 0; /* index into raw tokens */ +fError = 0; /* set true for invalid operand error */ +fDone = 0; /* Set when no more tokens are expected in operand */ +fOpenSQ = 0; /* keep track of [] */ + +/* flags for segment instruction prefix - NONE unless otherwise set */ +/* If it's a single token operand, take the fast, easy way out! */ + +if (rgTCnt[op] == 1) { + return (EvalOper1(op)); +} + +else { /* multiple tokens in operand */ + + /* with more than 1 token it is usually a memory reference + but not always. We will default to mem and change those we + find that aren't. */ + + rgOpType[op] = mem; + + /* Segment prefix? If so, set flag and eat 2 tokens */ + + if ((rgToken[op][0]==REGIST) && (is_rSEG(rgTID[op][0]))) { + if (rgToken[op][1] == COLON) { + switch (rgToken[op][0]) { + case rDS: OpPrefix |= fDSp; break; + case rES: OpPrefix |= fESp; break; + case rSS: OpPrefix |= fSSp; break; + case rFS: OpPrefix |= fFSp; break; + case rGS: OpPrefix |= fGSp; break; + case rCS: OpPrefix |= fCSp; break; + default:; + } + i += 2; /* skip rSEG and colon */ + } + else { + line_error(16); + return(0); + } + } + +/* Loop through the raw tokens looking for Base Reg, Index Reg, + Scale value, or displacement and setting varaibles as needed. +*/ + + while ((i < rgTCnt[op]) && + (!fError) && + (!fDone)) { + switch (rgToken[op][i]) { + + case REGIST: + if (is_r32(rgTID[op][i])) { /* check for Indx & Base Reg */ + if (rgToken[op][i+1] == STAR) { /* Index w/Scale */ + if (!(OpMType & fIndx)) { /* still OK */ + OpMType |= fIndx; + OpIndx = rgTID[op][i]; + if (rgToken[op][i+2] == NUMBER) { + switch (rgVal[op][i+2]) { + case 2: OpMType |= fScale2; break; + case 4: OpMType |= fScale4; break; + case 8: OpMType |= fScale8; break; + default: + line_error(17); + fError = 1; + } + } + else { + line_error(18); + fError = 1; + } + } + else { + line_error(19); + fError = 1; + } + i+=3; /* get past *NUMBER */ + } + /* Must be base, unless fBase true, then try Index */ + else { + if (!(OpMType & fBase)) { /* Base for sure */ + OpMType |= fBase; + OpBase = rgTID[op][i]; + i++; + } + else { /* try Index */ + if (!(OpMType & fIndx)) { /* It's free, use it */ + OpMType |= fIndx; + OpIndx = rgTID[op][i]; + i++; + } + } + } + } + else { /* must be 32 bit general purpose register */ + line_error(20); + fError = 1; + } + break; + + + case SYMOFF: /* One symbol was used by itself or in an expression */ + if (ExpType == 1) /* Local */ + symtype = lst[iExpSym].Type; + else if (ExpType == 2) { /* global */ + if (gst[iExpSym].Type & tEXTRN) + nExtRef = iExpSym; + symtype = gst[iExpSym].Type; + } + else /* Unknown - Forward */ + symtype = 0; + + if (OpMType & (fDisp32|fDisp8)) { /* Already a disp! */ + line_error(21); + fError = 1; + } + + /* Check for conditional jumps. */ + + else if ((CrntInst >= xJA) && + (CrntInst <= xJZ) && + (CrntInst != xJMP) && + (!(fOpenSQ))) + { + if (OpSize[op] & fShort) + rgOpType[op] = rel8; + else rgOpType[op] = relW; + if (fOpImm) { + OpImm2 = rgVal[op][i]; + fOpImm2 = 1; + } + else { + OpImm = rgVal[op][i]; + fOpImm = 1; + } + if (!symtype) + fForRef = 1; + } + + /* Check for JMP */ + + else if (CrntInst == xJMP) /* && (!(fOpenSQ))) */ + { + if ((OpSize[op] & fFar) || (symtype & tFAR)) { + rgOpType[op] = iSAD; + if (fOpImm) { + OpImm2 = rgVal[op][i]; + fOpImm2 = 1; + } + else { + OpImm = rgVal[op][i]; + fOpImm = 1; + } + } + else if (OpSize[op] & fShort) { + rgOpType[op] = rel8; + OpImm = rgVal[op][i]; + fOpImm = 1; + if (!symtype) + fForRef = 1; + } + else if (OpSize[op] & fFWord) { + rgOpType[op] = memF; /* memF = 32 disp which has 16:32 */ + OpMType |= fDisp32; + OpDisp = rgVal[op][i]; + if (symtype & CLABEL) + nFixUp = CCFIXTAG; + else if (symtype & DLABEL) + nFixUp = CDFIXTAG; + if (!symtype) + fForRef = 1; + } + else { + rgOpType[op] = relW; + OpImm = rgVal[op][i]; + fOpImm = 1; + if (!symtype) + fForRef = 1; + } + } + + /* Check for CALL */ + + else if ((CrntInst == xCALL) && (!(fOpenSQ))) + { + if ((OpSize[op] & fFar) || (symtype & tFAR)) { + rgOpType[op] = iSAD; + if (fOpImm) { + OpImm2 = rgVal[op][i]; + fOpImm2 = 1; + } + else { + OpImm = rgVal[op][i]; + fOpImm = 1; + } + } + else if (OpSize[op] & fFWord) { + rgOpType[op] = memF; /* memF = 32 disp which has 16:32 */ + OpMType |= fDisp32; + OpDisp = rgVal[op][i]; + if (symtype & CLABEL) + nFixUp = CCFIXTAG; + else if (symtype & DLABEL) + nFixUp = CDFIXTAG; + if (!symtype) + fForRef = 1; + } + else { /* Relative call */ + rgOpType[op] = relW; + if (!symtype) + fForRef = 1; + } + } + + /* Check for SGDT SIDT */ + + else if ((CrntInst == xSGDT) || (CrntInst == xSIDT)) + { + if (OpSize[op] & fFWord) { + rgOpType[op] = memF; /* memF = 32 disp which has 16:32 */ + OpMType |= fDisp32; + OpDisp = rgVal[op][i]; + if (symtype & CLABEL) + nFixUp = CCFIXTAG; + else if (symtype & DLABEL) + nFixUp = CDFIXTAG; + if (!symtype) + fForRef = 1; + } + } + + /* Check for Loop */ + + else if ((CrntInst >= xLOOP) && (CrntInst <= xLOOPZ)) + { + rgOpType[op] = rel8; + OpImm = rgVal[op][0]; + fOpImm = 1; + if (!symtype) + fForRef = 1; + } + else { + OpDisp = rgVal[op][i]; + OpMType |= fDisp32; + if (symtype & CLABEL) + nFixUp = CCFIXTAG; + else if (symtype & DLABEL) + nFixUp = CDFIXTAG; + if (!symtype) + fForRef = 1; + } + i++; + break; + + case NUMBER: /* can be 8 or 32 bit disp, or hard address */ + OpDisp = rgVal[op][i]; + if ((rgVal[op][i] >= -128) && (rgVal[op][i] <= 127)) + OpMType |= fDisp8; + else + OpMType |= fDisp32; + i++; + break; + + case OPENSQR: + if (fOpenSQ) { + line_error(23); + fError = 1; + } + else fOpenSQ = 1; + i++; + break; + case CLOSSQR: + if (!fOpenSQ) { + line_error(24); + fError = 1; + } + else fOpenSQ = 0; + i++; + break; + case COLON: /* for far addresses */ + i++; + break; + case PLUS: + i++; + break; + case rBYTE: + if ((!OpSize[op]) && (rgToken[op][i+1] == rPTR)) { + OpSize[op] |= fByte; + i+=2; + } + else { + line_error(25); + fError = 1; + } + break; + case rWORD: + if ((!OpSize[op]) && (rgToken[op][i+1] == rPTR)) { + OpSize[op] |= fWord; + i+=2; + } + else { + line_error(25); + fError = 1; + } + break; + case rDWORD: + if ((!OpSize[op]) && (rgToken[op][i+1] == rPTR)) { + OpSize[op] |= fDWord; + i+=2; + } + else { + line_error(25); + fError = 1; + } + break; + case rFWORD: + if ((!OpSize[op]) && (rgToken[op][i+1] == rPTR)) { + OpSize[op] |= fFWord; + i+=2; + } + else { + line_error(25); + fError = 1; + } + break; + case rNEAR: + if ((!OpSize[op]) && (rgToken[op][i+1] == rPTR)) { + OpSize[op] |= fNear; + i+=2; + } + else { + line_error(25); + fError = 1; + } + break; + case rFAR: + if ((!OpSize[op]) && (rgToken[op][i+1] == rPTR)) { + OpSize[op] |= fFar; + i+=2; + } + else { + line_error(25); + fError = 1; + } + break; + case rSHORT: + if (!OpSize[op]) { + OpSize[op] |= fShort; + i++; + } + else { + line_error(25); + fError = 1; + } + break; + default: { + line_error(32); + fprintf(lst_fh, " %d ", rgToken[op][i]); /* TESTING */ + i++; + } + + } /* switch */ + } /* while */ +} +if (fError) return(0); +if ((fDone) && (i< rgTCnt[op])) { + line_error(33); + return(0); + } + +return(1); + +} + +/******************************************** + Adds ALL forward reference to the Ref table. + This holds references to all foward addresses + (unknown) in the current module. + This stores all Refs UPPER case. +*********************************************/ +void ForRef(U8 type, S32 Offset) +{ +S32 i; + +if (pRefNext >= (pRefBuf + FREFBUFMAX)) + fatal_error("Forward Reference buffer overflow..."); +if (iRefNext >= FREFSMAX) + fatal_error("Forward Reference table overflow..."); + +/* Make a forward reference table entry */ + +strncpy(pRefNext, UString, UCBString); +pfrt[iRefNext].NameSz = UCBString; /* size of name */ +pfrt[iRefNext].Ptr = pRefNext; +pfrt[iRefNext].Line = lineno[level]; /* for error reporting */ +pfrt[iRefNext].Type = type; /* type of ref */ + + +pfrt[iRefNext].Offs = Offset; /* Offset to correction in CS or DS */ + +/* update for next symbol */ + +pRefNext += UCBString; +iRefNext++; + +} + +/******************************************** + Adds fixup table entries to be placed in + the run file. This includes DLL entries. +*********************************************/ + +void FixUp(U8 typef, S32 Offset, S32 iSymbol) +{ + +if (typef == CDFIXTAG) + nCDFix++; +else if (typef == DDFIXTAG) + nDDFix++; +else if (typef == DCFIXTAG) + nDCFix++; +else if (typef == CCFIXTAG) + nCCFix++; + + +if (iFUNext >= FIXUPSMAX) + fatal_error("Fixup Table overflow..."); +pfut[iFUNext].type = typef; +pfut[iFUNext].Offs = Offset; +pfut[iFUNext].iSym = iSymbol; /* global symbol entry for DLL */ + +iFUNext++; + +} + +/******************************************** + Adds External Reference to table. + This DOES NOT includes DLL Refs. + ETypes are the same as ForRef types + except there and no 8 bit externals. +*********************************************/ + +void ExtRef(U8 EType, S32 iSymbol) +{ + +if (iERefNext >= EREFSMAX) + fatal_error("External Reference Table overflow..."); + +if (fDataSeg) + ert[iERefNext].Offs = oNextData; +else { + ert[iERefNext].Offs = oNextCode; + } +ert[iERefNext].iSym = iSymbol; /* global symbol entry for external */ +ert[iERefNext].Type = EType; /* global symbol entry for external */ + +iERefNext++; +} + +/***************************************************** + Reads in all of the reserved words, numbers, math + operators, etc. that make up one operand. They are + read into one of 3 2D arrays as indicated by "op". + Integer rgTCnt[op] is number if items. A special + case for jump and call instructions is tested if + we end up with an Unknown Symbol as and operand. + We Error out if we have an UNKSYM without a + jump or call. +*****************************************************/ + +S32 GetOper(S32 op) +{ +S32 i, T; + +i = 0; +while (1) { + T = Parse(); + switch (T) { + case ZERO: + rgTCnt[op] = i; + if (i) return(1); + else return(0); + case REGIST: + rgTID[op][i] = TReg; + rgToken[op][i] = T; + break; + case NUMBER: /* check for special case of REG*2,*4,*8 */ + if ((i > 1) && + (rgToken[op][i-1] == STAR) && + (rgToken[op][i-2] == REGIST)) { + rgVal[op][i] = TNumber; + rgToken[op][i] = T; + break; /* only break here if we find special case */ + } /* Else fall thru to Expression */ + case LSYMBOL: + case SYMBOL: + case DOLLAR: /* These should all evaluate to a number!! */ + case OPENRND: + case MINUS: + case UNKSYM: + case rOFFSET: + if (Expression()) { + rgVal[op][i] = TNumber; + rgToken[op][i] = Token; /* Token instead of T (From Expr)*/ + } + else { + line_error(35); + return(0); + } + + break; + case COMMA: + if (!i) { + line_error(36); + return(0); + } + rgTCnt[op] = i; + ReturnToken(); + return(1); + case OPENSQR: + case CLOSSQR: + case STAR: + case PLUS: + case SLASH: + case SEMI: + case COLON: + case rFAR: + case rBYTE: + case rWORD: + case rDWORD: + case rFWORD: + case rPTR: + case rSHORT: + rgToken[op][i] = T; + break; + default: + line_error(38); + return(0); + } + i++; +} /* while */ +} + +/******************************************** + This finds the first matching entry in rgINS + by first matching the instruction number, + then matching operands. The table is indexed + with an array providing the first entry for + the instruction. This speed things up a bit. +*********************************************/ + +S32 INSEntry(S32 InsNum, S32 nOpers) +{ +S32 i; + + i = rgInsLookUp[InsNum]; + while (i <= nrgINS) { + + /* instruction entries of the same type + are all kept together. This is an early out. + */ + + if (rgINS[i][0] != InsNum) + return(0); /* couldn't find a match at all... */ + + /* See if all the operators match by calling is_Comp for each. + */ + + if ((is_Comp(i,0)) && + (is_Comp(i,1)) && + (is_Comp(i,2))) + + return(i); /* yes, they all match! */ + + i++; /* No, goto next entry */ + } +} + + +/******************************************** + EmitInst spits out the instruction bytes that + were encoded into variables by EncodeInst. + This handles output to the code segment + file as well as the text to the list file. + It updates the code segment address and + also adds fixup records as they are needed. + +The instruction (up to 16 bytes) is ordered +as follows: + Instruction Prefix 0 or 1 byte + Address Size Prefix 0 or 1 byte + Operand Prefix 0 or 1 byte + Segment Override 0 or 1 bytes + Opcode 1 or 2 bytes + MODR/M 0 or 1 bytes + SIB 0 or 1 bytes + Displacement 0,1,2 or 4 bytes + Immediate 0,1,2, or 4 bytes +**********************************************/ + +void EmitInst(void) +{ +U8 oppfx; +S8 sbyte; +S32 sword; +U32 i; /* used local to each section if needed */ + + + + /* + Instruction prefix: 0 or 1 byte (Lock, Rep, etc.) + */ + + if (InstPfx) { + if (InstPfx==xLOCK) { + if (fListA) { + Column += 2; + put_hexb(0x0F, lst_fh); + } + OutByteX(0xF0); + } + else if ((InstPfx==xREPNE) || (InstPfx==xREPNZ)) { + if (fListA) { + Column += 2; + put_hexb(0xF2, lst_fh); + } + OutByteX(0xf2); + } + else { /* Must be REP... */ + if (fListA) { + Column += 2; + put_hexb(0xF3, lst_fh); + } + OutByteX(0xf3); + } + if (fListA) + Column += fprintf(lst_fh, "| "); + } + +/* + Skip Address Size prefix: (67h) cause we aren't + doing USE16, nor do we support 16 bit addressing modes! +*/ + +/* Operand Size prefix: 0 or 1 (66h) */ + + if (OpSizeA & fWord) { + if (fListA) { + Column += 2; + put_hexb(0x66, lst_fh); + Column += fprintf(lst_fh, "| "); + } + OutByteX(0x66); + } + +/* Segment Override prefix */ + + switch (OpPrefix) { + case fDSp: oppfx = 0x3e; break; + case fESp: oppfx = 0x26; break; + case fSSp: oppfx = 0x36; break; + case fFSp: oppfx = 0x64; break; + case fGSp: oppfx = 0x65; break; + case fCSp: oppfx = 0x2e; break; + default: oppfx = 0; + } + if (oppfx) { + if (fListA) { + Column += 2; + put_hexb(oppfx, lst_fh); + Column += fprintf(lst_fh, "| "); + } + OutByteX(oppfx); + } + +/* OpCode byte 1 (optional) + bOpc1 was setup in EncodeInst (either 0 or 0Fh) +*/ + + if (bOpc1) { + if (fListA) { + Column += 2; + put_hexb(bOpc1, lst_fh); + Column += fprintf(lst_fh, " "); + } + OutByteX(bOpc1); + } + +/* OpCode byte 2 (always sent) */ + + if (fListA) { + Column += 2; + put_hexb(bOpc2, lst_fh); + Column += fprintf(lst_fh, " "); + } + + OutByteX(bOpc2); + +/* ModR/M (optional) */ + + if (fModRM) { + if (fListA) { + Column += 2; + put_hexb(bModRM, lst_fh); + Column += fprintf(lst_fh, " "); + } + OutByteX(bModRM); + } + +/* SIB (optional) */ + + if (fSIB) { + if (fListA) { + Column += 2; + put_hexb(bSIB, lst_fh); + Column += fprintf(lst_fh, " "); + } + OutByteX(bSIB); + } + +/* + Disp: 0, 1, 2 or 4 + A Displacement is a memory reference (an offset in a segment) + that is encoded as part of the instruction. The value to encode + is placed in OpDisp when the instruction is parsed and + evaluated. +*/ + + if (OpMType & fDisp32) { + + if (fListA) { + Column += 8; + put_hexd(OpDisp, lst_fh); + if ((nExtRef) || (fForRef)) + Column += fprintf(lst_fh, "r "); + else + Column += fprintf(lst_fh, " "); + } + if (nExtRef) + ExtRef(CSEGREF, nExtRef); + else if (fForRef) + ForRef(CSEGREF, oNextCode); + else if (nFixUp) + FixUp(nFixUp, oNextCode, 0); /* Code ref to data */ + OutDWordX(OpDisp); + } + + if (OpMType & fDisp8) { + + if (fListA) { + sbyte = OpDisp; + Column += 2; + put_hexb(sbyte, lst_fh); + Column += fprintf(lst_fh, " "); + } + OutByteX(OpDisp); + } + +/* + Immediate: 0, 1, 2 or 4 + The type of instruction operands tell us if we must encode + immediate values as part of the instruction. All instructions + have only one immediate value except ENTER. We make a check here + to determine if it is this instruction. + + imm8 = Immediate Byte in OpImm + imm16 = immediate 16 bit value in OpImm + immX = immediate value matching OpSize in OpImm + rel8 = immediate Byte calculated from a label + relW = immediate Word (16 or 32) calculated from a label + iSAD = immediate DWORD:WORD from Far Pointer (OpImm & OpImm2) + + immv1 is not encoded (implied by instruction) + immv3 is not encoded (also implied - INT 03 - Debug) + */ + if (fOpImm) + { + if ((rgINS[iInstEntry][1] == immX) || + (rgINS[iInstEntry][2] == immX) || + (rgINS[iInstEntry][3] == immX)) + { + if (OpSizeA & fByte) + { + if (fListA) + { + sbyte = OpImm; + Column += 2; + put_hexb(sbyte, lst_fh); + Column += fprintf(lst_fh, " "); + } + OutByteX(OpImm); + } + else if (OpSizeA & fWord) + { + if (fListA) + { + sword = OpImm; + Column += 4; + put_hexw(sword, lst_fh); + Column += fprintf(lst_fh, " "); + } + OutWordX(OpImm); + } + else { /* MUST be a DWord */ + if (fListA) { + Column += 8; + put_hexd(OpImm, lst_fh); + if (nFixUp) + Column += fprintf(lst_fh, "r "); + else + Column += fprintf(lst_fh, " "); + } + if (nExtRef) + ExtRef(CSEGREF, nExtRef); + else if (fForRef) + ForRef(CSEGREF, oNextCode); + else if (nFixUp) + FixUp(nFixUp, oNextCode, 0); /* Code ref to data */ + OutDWordX(OpImm); + } + } + + if ((rgINS[iInstEntry][1] == imm16) || + (rgINS[iInstEntry][2] == imm16) || + (rgINS[iInstEntry][3] == imm16)) { + if (fListA) { + Column += 4; + sword = OpImm; + put_hexw(sword, lst_fh); + Column += fprintf(lst_fh, " "); + } + OutWordX(OpImm); + } + else if ((rgINS[iInstEntry][1] == imm8) || + (rgINS[iInstEntry][2] == imm8) || + (rgINS[iInstEntry][3] == imm8) || + (rgINS[iInstEntry][1] == ims8) || + (rgINS[iInstEntry][2] == ims8) || + (rgINS[iInstEntry][3] == ims8)) + { + if (fListA) { + Column += 2; + sbyte = OpImm; + put_hexb(sbyte, lst_fh); + Column += fprintf(lst_fh, " "); + } + OutByteX(OpImm); + } + + /* Special check for Enter. It is only instructon with 2 Imms!*/ + + if (rgINS[iInstEntry][0] == xENTER) + { + if (fListA) { + Column += 2; + sbyte = OpImm2; + put_hexb(sbyte, lst_fh); + Column += fprintf(lst_fh, " "); + } + OutByteX(OpImm2); + } + + + /* With relative values for immediates, OpImm comes in as + the address of the target jump or call. We must take + the current code offset (of the next instruction) and + subtract it from the target (OpImm) to get the relative + jump value. If it is an UNKSYM we will put the value + of the target into the FRT to hold it and + do the math on the second pass of the machine code. + Math Example: + + oCode = 100 (next instruction) + Target = 50 + Jump = -50 (Target-Current) + + oCode = 100 (next instruction) + Target = 150 + Jump = 50 (Target-Current) + + Relative immediate values found in the GST as EXTERN + require an ERT entry so they can be fixed up when + the final code module is written to the run file. + + Relative immediate values found in the GST as PUBLICS + can be fixed up NOW. + + Relative immediate values NOT found are assumed local + and an entry is made in the FRT so they can be fixed + up when this code module is written to the main + temp code module. + */ + + if (rgINS[iInstEntry][1] == relW) { + if (nExtRef) { /* list external */ + OpImm = 0; + ExtRef(CCR32REF, nExtRef); + } + else if (fForRef) { /* list Forward Relative */ + OpImm = 0; + ForRef(CCR32REF, oNextCode); + } + else { /* Fix known ref */ + OpImm = OpImm - (oNextCode + 4); + } + + if (fListA) { + Column += 8; + put_hexd(OpImm, lst_fh); + if ((!fForRef) && (!nExtRef)) + Column += fprintf(lst_fh, " "); + else + Column += fprintf(lst_fh, "R "); + } + OutDWordX(OpImm); + } + + if (rgINS[iInstEntry][1] == rel8) { + if (!fForRef) { /* Fix KNOWN Relative */ + OpImm = OpImm - (oNextCode + 1); + if ((OpImm > 127) || (OpImm < -127)) + line_error(39); + } + else { /* Else List Unknown */ + ForRef(CCR8REF, oNextCode); + OpImm = 0; + } + + if (fListA) { + Column += 2; + sbyte = OpImm; + put_hexb(sbyte, lst_fh); + if ((!fForRef) && (!nExtRef)) + Column += fprintf(lst_fh, " "); + else + Column += fprintf(lst_fh, "R "); + } + OutByteX(OpImm); + } + + if (rgINS[iInstEntry][1] == iSAD) { + if (fListA) { + Column += 4; + sword = OpImm; + put_hexw(sword, lst_fh); + Column += fprintf(lst_fh, ":"); + Column += 4; + put_hexd(OpImm2, lst_fh); + Column += fprintf(lst_fh, " "); + } + OutWordX(OpImm); + OutDWordX(OpImm2); + } + } +} + + +/******************************************** + This encodes the instructions into bytes + and calls EmitInst() to put them into the + current code segment. The instruction can + be as long as 16 bytes if all options are used. + The order of the bytes and their possible + sizes are as follows: + Inst Prefix: 0 or 1 (Lock, Rep, etc.) + Address Size prefix: 0 or 1 (67h) - We don't use this + Operand Size prefix: 0 or 1 (66h) + Segment Override: 0 or 1 + OpCode: 1 or 2 + ModR/M: 0 or 1 + SIB: 0 or 1 + Disp: 0, 1, 2 or 4 + Immediate: 0, 1, 2 or 4 + This routine follows the guidance to build + instructions given in the rgINS table + (as bit flags). It calls EmitInst() to + emit the code, list-file information and + fixups to the FUT. + **********************************************/ +void EncodeInst(void) +{ +S8 fError; +S32 i; +U8 bTmp; + +/* +U8 bOpc1; Zero if not used THESE ARE GLOBAL... +U8 bOpc2; Always used +U8 bModRM; +U8 bSIB; +S8 fModRM; Is bModRM set/used? +S8 fSIB; Is bSIB set/used? +*/ + +fModRM = 0; /* not used by default */ +fSIB = 0; + + +/* SKIP the Address Size Prefix for now because we don't do 16 Bit + Effective addresses +*/ + + +/* + Now we will build the instruction in (up to) 4 temporary bytes. + We do it in temporary byte vars so we can see if an Operand Prefix + and a possible address fixup record is required before we + actually put it into the code segment. +*/ + +/* + The WORD forms of string instructions require us + to force a WORD size. We set this in the instruction table + as qUW in byte [4], +*/ + +if (rgINS[iInstEntry][4] & qUW) + OpSizeA |= fWord; + +/* Put in the first byte of Opcode from table (if required). qP0F is + set in rgINS[iInstEntry][4] if a 0Fh prefix is required for this inst. + A 0 in bObc1 indicates that this byte is NOT to be used. +*/ + +if (rgINS[iInstEntry][4] & qP0F) + bOpc1 = 0x0F; +else bOpc1 = 0; + +/* Get the Opcode from table into bOpc2 */ + +bOpc2 = rgINS[iInstEntry][5]; + +/* The flags zMR1, zMR2, zMOP, zAR1, and zAR2 all indicate that the + ModRM is needed. The following set of if-else statements checks these + flags and sets REG/OP field of MOD/RM byte if required. + OpSize should already be set. We also complete + the instruction encoding (with the exception of any immediate values) + if the other operand is a register. +*/ + +if (rgINS[iInstEntry][7] & zMR1) { + bModRM = rgINS[iInstEntry][6]; + fModRM = 1; + if (is_Reg(rgOpType[0])) + EncodeRegBits(rgOpReg[0], &bModRM, 3); + if (is_Reg(rgOpType[1])) { + EncodeRegBits(rgOpReg[1], &bModRM, 0); + bModRM |= 0xC0; /* indictes REG in RM field */ + } + } +else if (rgINS[iInstEntry][7] & zMR2) { + bModRM = rgINS[iInstEntry][6]; + fModRM = 1; + if (is_Reg(rgOpType[1])) + EncodeRegBits(rgOpReg[1], &bModRM, 3); + if (is_Reg(rgOpType[0])) { + EncodeRegBits(rgOpReg[0], &bModRM, 0); + bModRM |= 0xC0; /* indictes REG in RM field */ + } + } +else if (rgINS[iInstEntry][7] & zMOP) { + bModRM = rgINS[iInstEntry][6]; + fModRM = 1; + if (is_Reg(rgOpType[0])) { + EncodeRegBits(rgOpReg[0], &bModRM, 0); + bModRM |= 0xC0; /* indictes REG in RM field */ + } + } +else if (rgINS[iInstEntry][7] & zAR1) { + bTmp = 0; + EncodeRegBits(rgOpReg[0], &bTmp, 0); + bOpc2 += bTmp; + } +else if (rgINS[iInstEntry][7] & zAR2) { + bTmp = 0; + EncodeRegBits(rgOpReg[1], &bTmp, 0); + bOpc2 += bTmp; + } +else if ((rgINS[iInstEntry][7] & zRG1) && (rgOpType[0] != mem)) { + bModRM = rgINS[iInstEntry][6]; + fModRM = 1; + EncodeRegBits(rgOpReg[0], &bModRM, 3); + bModRM |= 0xC0; /* indictes REG in RM field */ + } + + + /* OpSize may not be required for many instructions, but we know + for a fact it MUST be known for memory operands! + */ + + if ((rgOpType[0] == mem) || + (rgOpType[1] == mem) || + (rgOpType[0] == memF)) { + if (!(OpSizeA & (fByte|fWord|fDWord|fFWord))) { + line_error(40); + return; + } + } + + /* + If zORD, see if we have word or dword register and OR the Opcode + (Opc2) with 01 if so. + */ + + if (rgINS[iInstEntry][7] & zORD) { + if (OpSizeA & (fWord | fDWord)) + bOpc2 |= 0x01; + } + + /* Perform the following additonal steps if we have a memory reference + as determined by iMemEntry. + */ + + fSIB = 0; + if (iMemEntry) { + + /* If SIB is needed (as determined from OpMType), get it and also + OR ModRM by required value from rgM32 table + */ + + bModRM |= rgM32[iMemEntry][2]; /* Use ModRM 'OR' value from table */ + if (rgM32[iMemEntry][1]) { /* is there an SIB byte? */ + bModRM &= 0x38; /* 00111000 leaves Reg bit on */ + bModRM |= rgM32[iMemEntry][2]; /* 'OR' ModRM with table value */ + bSIB = rgM32[iMemEntry][3]; + fSIB = 1; + } + + + /* At this point we have our Opcode, ModRM, and SIB (if required). + The MOD and SS bit are already filled in from the table. + This means we just stick the register values or bits for Disp etc + in the correct positions to complete it. + If we didn't have an SIB, we either have a single displacement, + a base or both. + */ + + if (!fSIB) { /* only a base, disp, or both */ + if (OpMType & fBase) + EncodeRegBits(OpBase, &bModRM, 0); + else + bModRM |= 0x05; /* only a disp32 */ + } + else { + if (OpMType & fBase) + EncodeRegBits(OpBase, &bSIB, 0); + else bModRM |= 0x20; /* else set [--][--] bits */ + if (OpMType & fIndx) + EncodeRegBits(OpIndx, &bSIB, 3); + } + } + + EmitInst(); + +} + + +/******************************************** + When the dispatcher detects an Instruction + it calls this code to read in (via parse) + the parametrs for the instruction and to + put together the opcodes. First we loop thru + and get up to 3 operands, then we evaluate + them (classify by type). Next we look up + the instruction and find a match for the + operand types they have specified, and + finally, we encode the instruction into the + code segment updating the code segment offset + pointer. +*********************************************/ +void Instruction(void) +{ +S32 i; +S8 fError; +S8 OpSizeTmp; + +fError = 0; +if (fDataSeg) { + line_error(41); + return; + } + +/* If the instruction is a prefix instruction, save it + and Parse again to get the real instruction */ + +if ((TInst==xREP) || (TInst==xREPE) || (TInst==xREPZ) || + (TInst==xREPNE) || (TInst==xREPNZ) || (TInst==xLOCK)) { + InstPfx = TInst; + i = Parse(); + if (i != INSTRU) { + line_error(42); + return; + } +} else InstPfx = 0; + +/* RESET all global instruction variables */ + +CrntInst = TInst; /* Save the instruction */ +nOperands = 0; /* none yet... */ +rgOpType[0] = 0; +rgOpType[1] = 0; +rgOpType[2] = 0; +OpMType = 0; /* char - memory type (a byte to compare to rgM32) */ +OpSize[0] = 0; /* char - Mem op size (fByte, fWord, fDword, fFword) */ +OpSize[1] = 0; /* char - Mem op size (fByte, fWord, fDword, fFword) */ +OpSizeA = 0; /* char - Mem op size (fByte, fWord, fDword, fFword) */ +OpSizeTmp = 0; /* char - Mem op size (fByte, fWord, fDword, fFword) */ +OpPrefix = 0; /* For Segment register prefix flags */ +OpDisp = 0; /* long - Displacement if fDisp8 or fDisp32 is TRUE */ +OpBase = 0; /* int - Base register if fBase is true */ +OpIndx = 0; /* int - Index register if fIndx is true */ +fOpImm = 0; /* No Immediate value yet */ +OpImm = 0; /* Default to 0 */ +fOpImm2 = 0; /* No second Immediate value yet */ +OpImm2 = 0; /* Default to 0 */ +nFixUp = 0; /* Fixup type if needed, else 0 */ +nExtRef = 0; /* GST entry if external ref was made */ +fForRef = 0; /* No Forward Ref in crnt inst yet */ +ExpType = 0; /* Type of symbol used in instruction */ +ExpType0 = 0; /* Type of symbol used in instruction */ +iExpSym = 0; /* Index into symtab for symbol if used */ +iExpSym0 = 0; /* Index into symtab for symbol if used */ + +if (GetOper(0)) { + nOperands++; + ExpType0 = ExpType; + iExpSym0 = iExpSym; + if ((Parse()== COMMA)) { + if (GetOper(1)) { + nOperands++; + if ((Parse()== COMMA)) { + if (GetOper(2)) { + nOperands++; + if (Parse()) { + line_error(33); + return; + } + } + } + } + } +} + +/* +At this point we have the instruction operands stored in +tokenized form in arrays. We now call EvalOper() which evaluates +the operands and fills in several variables that will assist in +building the instruction. EvalOper() returns 1 if it was a valid +operand, else 0. +*/ + +if (nOperands) { /* at least one */ + if (EvalOper(0)) { + if (nOperands > 1) { /* a second operand */ + if (EvalOper(1)) { + if (nOperands > 2) { /* a third??? - could be... */ + if (!(EvalOper(2))) + fError = 1; + } + } + else fError = 1; + } + } + else fError = 1; +} + +if (fError) return; + +/* + We must check to see what the word size of the instruction is + by looking at register sizes if any are included in the instruction. + If there are memory references or immediates involved, OpSizeA + MUST be set properly else it's an error! When there is a symbol involved + such as a move to a memory variable, we check the variable size and set + the OpSize to the variable size. If it's still not set, the line will + error out when we try to build the instruction because the caller + should have explicitly set the size (e.g., DWORD PTR ...). + + If a register is one of the operands in a memory transfer + (e.g., MOV [mem], EAX) then the move obviously defaults to the size + of the register (no ifs, ands, or buts). + + If there is no reg involved, we then look at 'OpSize[i]' + which may have been set by the size operators (e.g., DWORD PTR). + If it's zero we look at iExpSym which was set if there was a single + symbol involved in the memory reference. If there was, then we use it. + If it is blank, we error out cause we don't know what size memory + access we are doing! + This is done for each operand then the two are compared. If one is + zero we use the other, if both have something but are different + we error out! + +*/ + /* Find the first operand size */ + + /* First, let's look to see if they forced it! */ + + if (OpSize[0] & (fByte|fWord|fDWord|fFWord)) + + { /* do nothing */ } + + /* If they didn't force it, we'll look for the register size! */ + + else if (rgOpType[0] == r32) OpSize[0] |= fDWord; + else if (rgOpType[0] == r16) OpSize[0] |= fWord; + else if (rgOpType[0] == rSEG) OpSize[0] |= fWord; + else if (rgOpType[0] == r8) OpSize[0] |= fByte; + + /* Still nothing, so let's at symbols. */ + + else if (ExpType0 == 1) + { /* Local symbol */ + if (lst[iExpSym0].Type & sBYTE) OpSize[0] |= fByte; + else if (lst[iExpSym0].Type & sWORD) OpSize[0] |= fWord; + else if (lst[iExpSym0].Type & sDWORD) OpSize[0] |= fDWord; + else if (lst[iExpSym0].Type & sFWORD) OpSize[0] |= fFWord; + } + else if (ExpType0 == 2) + { /* Global Symbol */ + if (gst[iExpSym0].Type & sBYTE) OpSize[0] |= fByte; + else if (gst[iExpSym0].Type & sWORD) OpSize[0] |= fWord; + else if (gst[iExpSym0].Type & sDWORD) OpSize[0] |= fDWord; + else if (gst[iExpSym0].Type & sFWORD) OpSize[0] |= fFWord; + } + else if (ExpType0 == 3) + OpSize[0] |= fDWord; /* $ defaults to DWord */ + + + /* Find the second operand size. Check "forced fit" first */ + + if (OpSize[1] & (fByte|fWord|fDWord|fFWord)) + { /* do nothing */ } + + else if (rgOpType[1] == r32) OpSize[1] |= fDWord; + else if (rgOpType[1] == r16) OpSize[1] |= fWord; + else if (rgOpType[1] == rSEG) OpSize[1] |= fWord; + else if (rgOpType[1] == r8) OpSize[1] |= fByte; + + /* No registers, so let's look to see if they forced it! */ + + /* Still nothing, so let's at symbols. */ + + else if (ExpType == 1) + { /* Local symbol */ + if (lst[iExpSym].Type & sBYTE) OpSize[1] |= fByte; + else if (lst[iExpSym].Type & sWORD) OpSize[1] |= fWord; + else if (lst[iExpSym].Type & sDWORD) OpSize[1] |= fDWord; + else if (lst[iExpSym].Type & sFWORD) OpSize[1] |= fFWord; + } + else if (ExpType == 2) + { /* Global Symbol */ + if (gst[iExpSym].Type & sBYTE) OpSize[1] |= fByte; + else if (gst[iExpSym].Type & sWORD) OpSize[1] |= fWord; + else if (gst[iExpSym].Type & sDWORD) OpSize[1] |= fDWord; + else if (gst[iExpSym].Type & sFWORD) OpSize[1] |= fFWord; + } + else if (ExpType == 3) + OpSize[1] |= fDWord; /* $ defaults to DWord */ + + /* Special cases for operand size matching. */ + + if (CrntInst == xOUT) + OpSize[0] = OpSize[1]; + + +/* + Now that have the operands, and we know the TYPE of data (fByte etc.) + we call INSEntry to find the matching + entry in the array that describes each instruction. If we don't + find one that matches we error out telling them they have bad + operands. +*/ + +/* find first matching entry in rgINS */ + + iInstEntry = INSEntry(CrntInst, nOperands); + + if (!iInstEntry) { + line_error(44); + return; + } + + /* Now we make sure that we have set all operand sizes + and check for special cases as defined in rgINS. + */ + + if (rgINS[iInstEntry][7] & zSIZ) + OpSize[1] = OpSize[0]; + + if (!OpSize[1]) + OpSize[1] = OpSize[0]; + + if (!OpSize[0]) + OpSize[0] = OpSize[1]; + + /* Give them an error if operand sizes don't match */ + + if (nOperands > 1) + if (OpSize[0] != OpSize[1]) { + line_error(43); + return; + } + + OpSizeA = OpSize[0]; /* Set primary operand size */ + +/* If either the first or second operand was memory, we have to find + which entry in rgM32 it matches before we can encode it. If none + matches it is an invalid memory operand. If neither is a mem operand + we set iMemEntry to zero. There is the special case of moffs type + which is a short form of displacmement when moving data to and from thew + accumulator (e.g., MOV EAX, VAR1). We check for this and skip the + mem check if this is the instruction type we are on. +*/ + + if ((rgINS[iInstEntry][1] == moff) || (rgINS[iInstEntry][2] == moff)) + iMemEntry = 0; + else if ((rgOpType[0]==mem) || + (rgOpType[1]==mem) || + (rgOpType[0]==memF)) + { + + for (i=1; i 51) { + fprintf(lst_fh, "\r\n "); + Column=16; + } + } + OutByteX(TString[j]); + } + } + else { + line_error(46); + return; + } + break; + case rOFFSET: + if (StoreSize != 4) { + line_error(50); + return; + } + /* fall thru to evaluate & store value */ + case NUMBER: + case DOLLAR: /* These should all evaluate to a number. */ + case OPENRND: /* If it's SYMOFF, we do a fixup or Forward Ref */ + case MINUS: + case SYMBOL: + case LSYMBOL: + case UNKSYM: + fComma=0; + if (!(Expression())) /* 0 means error was emmited. */ + return; + + symtype = 0; /* default to no symbol type */ + nExtRef = 0; /* default to no external ref */ + + if ((Token==SYMOFF) || (Token==NUMOFF)) + { + if (ExpType == 1) /* Local */ + symtype = lst[iExpSym].Type; + else if (ExpType == 2) { /* global */ + symtype = gst[iExpSym].Type; + if (gst[iExpSym].Type & tEXTRN) + nExtRef = iExpSym; + } + } + + if (!fDUP) { + NSave = TNumber; + TSave = Token; + if (Parse() == rDUP) + { + nDUP = NSave; + fDUP = 1; + Parse(); + if (Token == OPENRND) { + if (!(Expression())) /* 0 means error was emitted.*/ + return; + } + else + line_error(47); + /* TNumber now has (VALUE) from DUP */ + } + else { + ReturnToken(); + TNumber = NSave; + Token = TSave; + } + } + + if (StoreSize==6) + { + if (fColon) { + fColon=0; /* reset it */ + if (fListA) { + sword = TNumber; + Column += 4; + put_hexw(sword, lst_fh); + Column += fprintf(lst_fh, " "); + } + OutWordX(TNumber); + } + else { + fExpectColon = 1; + if (fListA) { + Column += 8; + put_hexd(TNumber, lst_fh); + Column += fprintf(lst_fh, " "); + } + OutDWordX(TNumber); + } + } + else if (StoreSize==4) { + if (fDUP) + { + if (fListA) { + if ((Token == SYMOFF) || (Token == NUMOFF)) + Column += fprintf(lst_fh, "%08lX * (%08lXr)",nDUP,TNumber); + else + Column += fprintf(lst_fh, "%08lX * (%08lX)",nDUP,TNumber); + } + while (nDUP--) + { + if ((Token==SYMOFF) || (Token==NUMOFF)) + { + if (fDataSeg) { /* Data Seg */ + if (nExtRef) + ExtRef(DSEGREF, iExpSym); + else if (!symtype) + ForRef(DSEGREF, oNextData); + else if (symtype & CLABEL) + FixUp(DCFIXTAG, oNextData, 0); + else if (symtype & DLABEL) + FixUp(DDFIXTAG, oNextData, 0); + } + else { /* Code Seg */ + if (nExtRef) + ExtRef(CSEGREF, iExpSym); + if (!symtype) + ForRef(CSEGREF, oNextCode); + else if (symtype & CLABEL) + FixUp(CCFIXTAG, oNextCode, 0); + else if (symtype & DLABEL) + FixUp(CDFIXTAG, oNextCode, 0); + } + } + OutDWordX(TNumber); + } + } + else { + if (fListA) + { + if ((Token == SYMOFF) || (Token == NUMOFF)) + Column += fprintf(lst_fh, " %08lXr", TNumber); + else + Column += fprintf(lst_fh, " %08lX", TNumber); + } + + /* Fixup & Forref here! */ + if ((Token==SYMOFF) || (Token==NUMOFF)) + { + if (fDataSeg) + { /* Data Seg */ + if (nExtRef) + ExtRef(DSEGREF, iExpSym); + else if (!symtype) + ForRef(DSEGREF, oNextData); + else if (symtype & CLABEL) + FixUp(DCFIXTAG, oNextData, 0); + else if (symtype & DLABEL) + FixUp(DDFIXTAG, oNextData, 0); + } + else + { /* Code Seg */ + if (nExtRef) + ExtRef(CSEGREF, iExpSym); + else if (!symtype) + ForRef(CSEGREF, oNextCode); + else if (symtype & CLABEL) + FixUp(CCFIXTAG, oNextCode, 0); + else if (symtype & DLABEL) + FixUp(CDFIXTAG, oNextCode, 0); + } + } + OutDWordX(TNumber); + } + } + else if (StoreSize==2) { + if (fDUP) { + if (fListA) + Column += fprintf(lst_fh, "%08lX * (%04lX) ",nDUP,TNumber); + while (nDUP--) + OutWordX(TNumber); + } + else { + if (fListA) + Column += fprintf(lst_fh, "%04lX ", TNumber); + OutWordX(TNumber); + } + } + else { + if (fDUP) { + if (fListA) + Column += fprintf(lst_fh, "%08lX * (%02lX) ",nDUP,TNumber); + while (nDUP--) + OutByteX(TNumber); + } + else { + if (fListA) + Column += fprintf(lst_fh, "%02lX ", TNumber); + OutByteX(TNumber); + } + } + break; + case COMMA: /* Just eat the comma */ + if (fComma) { + line_error(48); + return; + } + fComma = 1; + break; + case COLON: + fComma=0; + if ((StoreSize == 6) && (fExpectColon)) { + fColon = 1; + fExpectColon = 0; + } + else { + line_error(49); + return; + } + break; + case ZERO: + if (fComma) fMoreStorage = 1; + return; + default: { + line_error(51); + fMoreStorage = 0; + return; + } + } +} +} + +/******************************************** + Add new GLOBAL symbol to table (TString). + Then parse again to hand off to + proper function. This stores all + Symbols UPPER case. +*********************************************/ +void NewSymbol() +{ +S32 i; +S8 fColon, fStorage; + + if ((pSymNext + CBString) >= (pSymBuf + SYMBUFMAX)) + fatal_error("Symbol buffer overflow..."); + if (iSymNext >= SYMSMAX) + fatal_error("Symbol table overflow..."); + + strncpy(pSymNext, TString, CBString); + gst[iSymNext].Size = CBString; + gst[iSymNext].Type = 0; /* initialize type */ + gst[iSymNext].Ptr = pSymNext; + gst[iSymNext].Line = lineno[level]; + gst[iSymNext].Offs = 0; + + /* All declarations that reach NewSymbol are either at + level 0 or defined as PUBLIC or EXTERN. + */ + + if (fExtern) + gst[iSymNext].Type |= tEXTRN; + else + gst[iSymNext].Type |= tPUBLIC; + + if (fFarLabel) gst[iSymNext].Type |= tFAR; + + if (fDataSeg) { + if (!fExtern) + gst[iSymNext].Offs = oNextData; + gst[iSymNext].Type |= DLABEL; + } + else { + if (!fExtern) + gst[iSymNext].Offs = oNextCode; + gst[iSymNext].Type |= CLABEL; + } + + /* update for next symbol */ + pSymNext += CBString; + iSymNext++; + + + /* Now, parse again and hand off. We have just added a symbol + so expect to see an EQU, COLON or Storage statement. + If we don't see one of these it's an error unless it's an extern. + If we see a COLON we parse again and expect an instruction or EOL! + */ + + fStorage = 0; + fColon=0; + i = Parse(); + + if (i == COLON) { + fColon = 1; + if (fDataSeg) { + line_error(49); + return; + } + i = Parse(); + } + + switch(i) { /* parse returns Token */ + case INSTRU: + if (fDataSeg) { + line_error(41); + return; + } + if (!fColon) { + line_error(54); + return; + } + Instruction(); + break; + case rDB: + gst[iSymNext-1].Type |= sBYTE; /* type */ + fStorage = 1; + break; + case rDW: + gst[iSymNext-1].Type |= sWORD; /* type */ + fStorage = 1; + break; + case rDD: + gst[iSymNext-1].Type |= sDWORD; /* type */ + fStorage = 1; + break; + case rDF: + if ((!fDataSeg) && (!fColon)) { + line_error(54); + return; + } + gst[iSymNext-1].Type |= sFWORD; /* type */ + fStorage = 1; + break; + case rEQU: + line_error(55); + /* AddMacro(); */ + break; + case COLON: + if (fExtern) + return; + case ZERO: + if ((fDataSeg) && (!fExtern)) + line_error(56); + break; + default: + if (fDataSeg) + line_error(56); + } + + if (gst[iSymNext-1].Type & tEXTRN) + fStorage = 0; + + if (fStorage) + Storage(); +} + +/******************************************** + This changes an EXTRN entry in the gst to + a PUBLIC once we find it. This checks to + make sure the extern declaration was the + same type as this public. +*********************************************/ + +void MakePublic(void) +{ +S32 i; +S8 fColon, fStorage; + + if (gst[TSymnum].Type & tPUBLIC) { + line_error(64); + return; + } + + if ((fDataSeg) && (!(gst[TSymnum].Type & DLABEL))) { + line_error(69); + return; + } + + if ((!fDataSeg) && (!(gst[TSymnum].Type & CLABEL))) { + line_error(69); + return; + } + + gst[TSymnum].Type |= tPUBLIC; /* Turn ON Public */ + gst[TSymnum].Type &= ~tEXTRN; /* Turn off EXTERN */ + + if (fDataSeg) + gst[TSymnum].Offs = oNextData; + else + gst[TSymnum].Offs = oNextCode; + + /* Now, parse again and hand off. We have just added a symbol + so expect to see an EQU, COLON or Storage statement. + If we don't see one of these it's an error unless it's an extern. + If we see a COLON we parse again and expect an instruction or EOL! + */ + +fStorage = 0; +fColon=0; +i = Parse(); + +if (i == COLON) { + fColon = 1; + if (fDataSeg) { + line_error(49); + return; + } + i = Parse(); +} + +switch(i) { /* parse returns Token */ + case INSTRU: + if (fDataSeg) { + line_error(41); + return; + } + if (!fColon) { + line_error(54); + return; + } + Instruction(); + break; + case rDB: + gst[TSymnum].Type |= sBYTE; /* type */ + fStorage = 1; + break; + case rDW: + gst[TSymnum].Type |= sWORD; /* type */ + fStorage = 1; + break; + case rDD: + gst[TSymnum].Type |= sDWORD; /* type */ + fStorage = 1; + break; + case rDF: + if ((!fDataSeg) && (!fColon)) { + line_error(54); + return; + } + gst[TSymnum].Type |= sFWORD; /* type */ + fStorage = 1; + break; + case rEQU: + line_error(55); + break; + case COLON: + return; + default: + if (fDataSeg) + line_error(56); + } + +if (fStorage) + Storage(); + +} + + +/******************************************** + This checks to ensure multiple externs are + the same type when we run across them, and + also that an extern is the same type if + the public is already declared. +*********************************************/ +void CheckExtern(void) +{ + /* Check to make sure new extern and symbol are same type */ + + if ((fDataSeg) && (!(gst[TSymnum].Type & DLABEL))) { + line_error(69); + return; + } + + if ((!fDataSeg) && (!(gst[TSymnum].Type & CLABEL))) { + line_error(69); + return; + } +} + + +/******************************************** + Add new LOCAL symbol to table (TString). + Then parse again to hand off to + proper function. This stores all + Symbols UPPER case. +*********************************************/ +void NewLSymbol(void) +{ +S32 i; +S8 fColon, fStorage; + +if ((pLSymNext + CBString) >= (pLSymBuf + LSYMBUFMAX)) + fatal_error("Local symbol buffer overflow..."); +if (iLSymNext >= LSYMSMAX) + fatal_error("Local symbol table overflow..."); + +strncpy(pLSymNext, TString, CBString); +lst[iLSymNext].Size = CBString; +lst[iLSymNext].Type = 0; /* initialize type */ +lst[iLSymNext].Ptr = pLSymNext; +lst[iLSymNext].Line = lineno[level]; + +if (fDataSeg) { + lst[iLSymNext].Offs = oNextData; + lst[iLSymNext].Type |= DLABEL; + } +else { + lst[iLSymNext].Offs = oNextCode; + lst[iLSymNext].Type |= CLABEL; + } + +/* update for next symbol */ +pLSymNext += CBString; +iLSymNext++; + +/* Now, parse again and hand off. We have just added a symbol +so expect to see an EQU, COLON or Storage statement. +If we don't see one of these it's an error! +If we see a COLON we parse again and expect an instruction or EOL! + */ + +fStorage = 0; +fColon=0; +i = Parse(); + +if (i == COLON) { + fColon = 1; + if (fDataSeg) { + line_error(49); + return; + } + i = Parse(); +} + +switch(i) { /* parse returns Token */ + case INSTRU: + if (fDataSeg) { + line_error(41); + return; + } + if (!fColon) { + line_error(54); + return; + } + Instruction(); + break; + case rDB: + lst[iLSymNext-1].Type |= sBYTE; /* type */ + fStorage = 1; + break; + case rDW: + lst[iLSymNext-1].Type |= sWORD; /* type */ + fStorage = 1; + break; + case rDD: + lst[iLSymNext-1].Type |= sDWORD; /* type */ + fStorage = 1; + break; + case rDF: + if ((!fDataSeg) && (!fColon)) { + line_error(54); + return; + } + lst[iLSymNext-1].Type |= sFWORD; /* type */ + fStorage = 1; + break; + case rEQU: + AddMacro(); + break; + case COLON: + return; + default: + if (fDataSeg) + line_error(56); + } + +if (lst[iLSymNext-1].Type & tEXTRN) + fStorage = 0; + +if (fStorage) + Storage(); + +} + +/***************************************** + After we transition from level 1 back to + level 0 we go back to the point in the + code or data file where we began writing this + section and resolve all forward code + and local data references. These will be + referenced in the module we just finished. + ******************************************/ + +void Resolve(void) +{ +long i, isym; +S32 Relative; +S32 Partial; +S32 AddFix; + + i = 0; + + while (i < iRefNext) /* While there are forward references */ + { + if (pfrt[i].Type == DSEGREF) /* Ref is in DSEG */ + { + seekDS(pfrt[i].Offs - DataOffset); + readDS(&Partial, 4); + seekDS(pfrt[i].Offs - DataOffset); + AddFix = pfrt[i].Offs - DataOffset; + } + else /* Ref is in CSEG */ + { + seekCS(pfrt[i].Offs - CodeOffset); + + if (pfrt[i].Type == CSEGREF) /* IT'S ABSOLUTE! */ + { + readCS(&Partial, 4); + seekCS(pfrt[i].Offs - CodeOffset); + AddFix = pfrt[i].Offs - CodeOffset; + } + } + /* We are where we should write the reference + now we need to find it in the local symbol table + and calculate the proper offset. The calculation + is different for Relative and absolute references. + For Relative, we subtract the address where the correction + is going to be stored from the offset of reference. + For Absolute, we read what was already at the address + and add it to the offset of the referenced item. + Both of these are also adjusted for the Virtual segment offset. + */ + + /* Look in the Local Symbol table first! */ + + isym = findLsymbol(pfrt[i].Ptr, pfrt[i].NameSz); + + if (isym) /* we found it! */ + { + if (pfrt[i].Type == CCR8REF) /* 8 bit relative */ + { + Relative = lst[isym].Offs - (pfrt[i].Offs - CodeOffset + 1); + OutByteCS(Relative); + } + else if (pfrt[i].Type == CCR32REF) /* 32 bit relative */ + { + /* Fixed to make relatives ok in Virtual Segs */ + + Relative = (lst[isym].Offs - CodeOffset) - + (pfrt[i].Offs - CodeOffset + 4); + OutDWordCS(Relative); + } + else if (pfrt[i].Type == CSEGREF) /* 32 bit absolute */ + { + Partial += lst[isym].Offs; + + if (lst[isym].Type & CLABEL) + FixUp(CCFIXTAG, AddFix, 0); + else if (lst[isym].Type & DLABEL) + FixUp(CDFIXTAG, AddFix, 0); + + OutDWordCS(Partial); + } + else if (pfrt[i].Type == DSEGREF) + { + Partial += lst[isym].Offs; /* RAB was + DataOffset */ + + if (lst[isym].Type & CLABEL) + FixUp(DCFIXTAG, AddFix, 0); + else if (lst[isym].Type & DLABEL) + FixUp(DDFIXTAG, AddFix, 0); + + OutDWordDS(Partial); + } + } + else /* Look in Global table */ + { + + isym = findGsymbol(pfrt[i].Ptr, pfrt[i].NameSz); + + if (isym) + + { /* we found it! */ + + + if (pfrt[i].Type == CCR8REF) { /* 8 bit relative */ + Relative = gst[isym].Offs - (pfrt[i].Offs - CodeOffset + 1); + OutByteCS(Relative); + } + else if (pfrt[i].Type == CCR32REF) { /* 32 bit relative */ + Relative = gst[isym].Offs - (pfrt[i].Offs - CodeOffset + 4); + OutDWordCS(Relative); + } + else if (pfrt[i].Type == CSEGREF) { + Partial += gst[isym].Offs; + + if (gst[isym].Type & CLABEL) + FixUp(CCFIXTAG, AddFix, 0); + else if (gst[isym].Type & DLABEL) + FixUp(CDFIXTAG, AddFix, 0); + + OutDWordCS(Partial); + } + else if (pfrt[i].Type == DSEGREF) + { + Partial += gst[isym].Offs; + + if (gst[isym].Type & CLABEL) + FixUp(DCFIXTAG, AddFix, 0); + else if (gst[isym].Type & DLABEL) + FixUp(DDFIXTAG, AddFix, 0); + + OutDWordDS(Partial); + } + } + else + prev_error("Unresolved symbol in current module", pfrt[i].Line); + } + i++; + } + + ics = oNextCode - CodeOffset; + ids = oNextData - DataOffset; + +} + +/***************************************** + When we have processed all the source + we call this to resolve ALL externals. + ******************************************/ + +void ResolveExt(void) +{ +long i, isym; +S32 Relative; +S32 Partial; +S32 AddFix; +char name[31]; + +i = 0; +Partial = 0; +Relative = 0; +AddFix = 0; + +while (i < iERefNext) { /* While there are unresolved externals */ + + /* See if ref is in GST as PUBLIC */ + + isym = ert[i].iSym; + + if (gst[isym].Type & tPUBLIC) { + + if (ert[i].Type == DSEGREF) { /* Ref is in DSEG */ + + seekDS(ert[i].Offs - DataOffset); + readDS(&Partial, 4); + seekDS(ert[i].Offs - DataOffset); + AddFix = ert[i].Offs - DataOffset; + } + else { /* Ref is in CSEG */ + + seekCS(ert[i].Offs - CodeOffset); + + if (ert[i].Type == CSEGREF) { /* and IT'S ABSOLUTE! */ + readCS(&Partial, 4); + seekCS(ert[i].Offs - CodeOffset); + AddFix = ert[i].Offs - CodeOffset; + } + } + /* We are where we should write the reference + now we need to use the index in the external ref + table to see if it has been defined PUBLIC. + If so, we resolve it, else we error out. + To resolve it, the calculation is different for Relative + and absolute references. + For Relative, we subtract the address where the correction + is going to be stored from the offset of reference. + For Absolute, we read what was already at the address + and add it to the offset of the referenced item. + Both of these are also adjusted for the Virtual segment offset. + */ + + if (ert[i].Type == CCR32REF) { /* 32 bit relative */ + + /* Fixed to make relatives ok in Virtual Segs */ + + Relative = (gst[isym].Offs - CodeOffset) - + (ert[i].Offs - CodeOffset + 4); + OutDWordCS(Relative); + } + else if (ert[i].Type == CSEGREF) { + Partial += gst[isym].Offs; + + if (gst[isym].Type & DLABEL) + FixUp(CDFIXTAG, AddFix, 0); + else if (gst[isym].Type & CLABEL) + FixUp(CCFIXTAG, AddFix, 0); + + OutDWordCS(Partial); + } + else if (ert[i].Type == DSEGREF) { + Partial += gst[isym].Offs; + + if (gst[isym].Type & CLABEL) + FixUp(DCFIXTAG, AddFix, 0); + else if (gst[isym].Type & DLABEL) + FixUp(DDFIXTAG, AddFix, 0); + + OutDWordDS(Partial); + } + } + else { + strncpy(name, gst[isym].Ptr, gst[isym].Size); + name[gst[isym].Size] = '\0'; + fprintf(lst_fh, "Unresolved external: %s\n", name); + Column = 0; + ++error_count; + } +i++; +} /* while more Erefs */ + +ics = oNextCode - CodeOffset; +ids = oNextData - DataOffset; + +} + +/***************************************** + If there were no errors, and all looks + well, we build the run file. This consists + of building the required tags in order + and writing them to the file with the + data. +******************************************/ + +void BuildRunFile(void) +{ +unsigned char b; +long i; +long sdata; + + tag.id = IDTAG; /* File type */ + tag.len = 1; + fwrite(&tag, 5, 1, run_fh); /* Write the tag record */ + fwrite(&filetype, 1, 1, run_fh); /* Write the filetype */ + + /* Version tag goes here */ + /* DatTime tag goes here */ + /* Comment tag(s) goes here */ + + tag.id = SEGTAG; /* Initial Segment Sizes */ + tag.len = 12; + fwrite(&tag, 5, 1, run_fh); /* Write the tag record */ + fwrite(&StackTotal, 4, 1, run_fh); /* Write the Stacktotal */ + sdata = oNextCode - CodeOffset; /* Size of CS.TMP */ + fwrite(&sdata, 4, 1, run_fh); /* Write the Code Size */ + sdata = oNextData - DataOffset; /* Size of DS.TMP */ + fwrite(&sdata, 4, 1, run_fh); /* Write the Data Size */ + + printf("Stack Size: %ld\r\n", StackTotal); + printf("Code Size: %ld\r\n", oNextCode - CodeOffset); + printf("Data Size: %ld\r\n", oNextData - DataOffset); + + tag.id = DOFFTAG; /* Assumed Data Offset */ + tag.len = 4; + fwrite(&tag, 5, 1, run_fh); /* Write the tag record */ + fwrite(&DataOffset, 4, 1, run_fh); /* Write the data */ + + tag.id = COFFTAG; /* Assumed Code Offset */ + tag.len = 4; + fwrite(&tag, 5, 1, run_fh); /* Write the tag record */ + fwrite(&CodeOffset, 4, 1, run_fh); /* Write the data */ + + tag.id = STRTTAG; /* Starting Address */ + tag.len = 4; + fwrite(&tag, 5, 1, run_fh); /* Write the tag record */ + fwrite(&StartAddr, 4, 1, run_fh); /* Write the data */ + + tag.id = CODETAG; /* Code Segment */ + tag.len = oNextCode - CodeOffset; /* Size of CS.TMP */ + fwrite(&tag, 5, 1, run_fh); /* Write the tag record */ + + sdata = tag.len; /* WRITE the Code seg */ + fwrite(pcsbuf, 1, sdata, run_fh); + + tag.id = DATATAG; /* Data Segment */ + tag.len = oNextData - DataOffset; /* Size of DS.TMP */ + fwrite(&tag, 5, 1, run_fh); /* Write the tag record */ + + sdata = tag.len; /* WRITE the Data seg */ + fwrite(pdsbuf, 1, sdata, run_fh); + + if (nCDFix) { + tag.id = CDFIXTAG; /* CSEG Data Fixups */ + tag.len = nCDFix * 4; /* Count * 4 of Fixups */ + fwrite(&tag, 5, 1, run_fh); /* Write the tag record */ + i = iFUNext; + while (i--) { /* Write CD fixups */ + if (pfut[i].type == CDFIXTAG) + fwrite(&pfut[i].Offs, 1, 4, run_fh); + } + } + + if (nCCFix) { + tag.id = CCFIXTAG; /* CSEG Code Fixups */ + tag.len = nCCFix * 4; /* Count * 4 of Fixups */ + fwrite(&tag, 5, 1, run_fh); /* Write the tag record */ + i = iFUNext; + while (i--) { /* Write CC fixups */ + if (pfut[i].type == CCFIXTAG) + fwrite(&pfut[i].Offs, 1, 4, run_fh); + } + } + + if (nDDFix) { + tag.id = DDFIXTAG; /* DESG Data Fixups */ + tag.len = nDDFix * 4; /* Count * 4 of Fixups */ + fwrite(&tag, 5, 1, run_fh); /* Write the tag record */ + i = iFUNext; + while (i--) { /* Write DD fixups */ + if (pfut[i].type == DDFIXTAG) + fwrite(&pfut[i].Offs, 1, 4, run_fh); + } + } + + if (nDCFix) { + tag.id = DCFIXTAG; /* DESG Code Fixups */ + tag.len = nDCFix * 4; /* Count * 4 of Fixups */ + fwrite(&tag, 5, 1, run_fh); /* Write the tag record */ + i = iFUNext; + while (i--) { /* Write DC fixups */ + if (pfut[i].type == DCFIXTAG) + fwrite(&pfut[i].Offs, 1, 4, run_fh); + } + } + + /* DLL Address fixup tag goes here */ + /* DLL Public tag goes here */ + + tag.id = ENDTAG; /* End Tag */ + tag.len = 4; /* Size of CS.TMP */ + fwrite(&tag, 5, 1, run_fh); /* Write the tag record */ + sdata = 0; + fwrite(&sdata, 4, 1, run_fh); /* Write the tag record */ + +} + + +/***************************************** + Reads a whole line into line buffer. +******************************************/ + +S32 readline(void) +{ +U32 i; +U8 *pLine; + +if (!(fgets(line_ptr = line_buf0, 100, src_fh[level]))) +{ + + if (level) { /* we are in a nested include */ + fclose(src_fh[level]); + --level; + if (level==0) { /* back up one level */ + + /* Processes forward references from this module */ + Resolve(); + + if (fSymDump) { + DumpLSymbols(); + DumpFRT(); + } + + /* Clear local symbol, forward refs, & macro tables */ + + iLSymNext = 1; /* 1st entry. */ + pLSymNext = pLSymBuf; /* beginning of buffer */ + + iRefNext = 0; /* 1st entry. */ + pRefNext = pRefBuf; /* Allocate memory - Was RefBuf */ + + iMacNext = 0; /* 1st entry */ + pMacNext = pMacBuf; /* Begining of buffer */ + + + } + if (fListA) + fprintf(lst_fh, "\r\n "); + fprintf(lst_fh, "CONTINUING-> %s, Level:%d\r\n", srcname[level],level); + fprintf(lst_fh, "\r\n"); + + if (lineno[level]) --lineno[level]; + fContinue = 1; + } + else + { /* We are at the end of the ATF file */ + + /* Processes forward references from Level 0 */ + Resolve(); + + if (fSymDump) + { + DumpGSymbols(); + DumpFRT(); + } + + if (!fStart) + line_error(12); /* Starting address not found */ + + if (!error_count) + ResolveExt(); + + printf("%d Errors\r\n%d Warnings\r\n", error_count, warn_count); + + if (fListA | fListE) + fprintf(lst_fh,"%d Errors\r\n%d Warnings\r\n", + error_count,warn_count); + + if (!error_count) + { + printf("Building Run file...\r\n"); + BuildRunFile(); + printf(" Done.\r\n"); + } + + fclose(lst_fh); + fclose(src_fh[level]); + exit(1); + } + } + + list_buf[0] = 0; + if (fListA) { + pLine = line_ptr; + i=0; + while (isspace(*pLine)) pLine++; + while ((*pLine) && (*pLine != ';') && (*pLine != 0x0A)) + list_buf[i++] = *pLine++; + while ((i) && (list_buf[i-1] == ' ')) --i; /* eat trailing spaces */ + list_buf[i] = 0; /* null terminate */ + if (i) fLineIn = 1; + else fLineIn = 0; + } + ++lineno[level]; + return(1); +} + + +/******************************************** + Dispatch calls Parse from the beginning + of a line and calls the proper routine + based on what it finds (from Parse()). + Dispatch calls readline to get a new line + after each of the line-specific modules + gets done with it's line or lines(s). +*********************************************/ + +void Dispatch(void) +{ +S32 i, j; +S8 st[80]; + +while (1) { + readline(); + + if (fContinue) { /* We have just returned from an include */ + fContinue = 0; /* and must reread the line without processing */ + continue; + } + + if (lineno[level] == 1) { + if (fListA) + fprintf(lst_fh, "\r\n "); + fprintf(lst_fh, "PROCESSING-> %s, Level:%d\r\n", srcname[level], level); + } + + if (fListA) { + Column = fprintf(lst_fh, "%06d ", lineno[level]); + } + + fPublic = 0; + fExtern = 0; + fFarLabel = 0; + + i = Parse(); + if (fMoreStorage) + Storage(); + else switch (i) { + case INSTRU: + if (fListA) + Column += fprintf(lst_fh, "%08lX ", *pNextAddr); + Instruction(); + break; + case REGIST: + line_error(63); + break; + case SYMBOL: + line_error(64); + break; + case LSYMBOL: + line_error(65); + break; + case STRING: + case NUMBER: + line_error(66); + break; + case rPUBLIC: + fPublic = 1; + if (fListA) + Column += fprintf(lst_fh, "%08lX ", *pNextAddr); + j = Parse(); + if (j==SYMBOL) + MakePublic(); + else if (j==UNKSYM) + NewSymbol(); + else + line_error(67); + break; + case rEXTRN: + fExtern = 1; + if (fListA) + Column += fprintf(lst_fh, "%08lX ", *pNextAddr); + j = Parse(); + if (j==SYMBOL) + CheckExtern(); + else if (j==UNKSYM) + NewSymbol(); + else + line_error(67); + break; + case UNKSYM: + if (fListA) + Column += fprintf(lst_fh, "%08lX ", *pNextAddr); + if (level) + NewLSymbol(); + else + NewSymbol(); + break; + case DOT: + Command(); + break; + case rDB: + case rDD: + case rDW: + case rDF: + if (fListA) + Column += fprintf(lst_fh, "%08lX ", *pNextAddr); + Storage(); + break; + case ZERO: + break; + default: + line_error(68); + break; + } + + if ((fLineIn) && (fListA)) { + while (Column < 53) Column += fprintf(lst_fh, " "); + fprintf(lst_fh, "%s", list_buf); + } + if (Column) + fprintf(lst_fh, "\r\n"); + + } /* while */ +} + +/********************* +* Main program +**********************/ + +void main(S32 argc, S8 *argv[]) +{ +S8 *ptr, *pname; +S32 i, j, fdone; +U32 erc; + + lst_fh = stdout; /* default the list file */ + + for(i=1; i < argc; ++i) { + ptr = argv[i]; + if (*ptr == '/') { + ptr++; + switch(*ptr) { + case 'L' : /* List file ON */ + case 'l' : + fListA = 1; + break; + case 'S' : /* Dump Symbols */ + case 's' : + fSymDump = 1; + break; + case 'E' : /* List file ON for errors/warns only */ + case 'e' : + fListE = 1; + break; + case 'D' : /* Process as DLL */ + case 'd' : + filetype = 2; + break; + case 'V' : /* Process as Devive Driver */ + case 'v' : + filetype = 3; + break; + default: + fatal_error("Invalid option\n"); + break; + } + } + else { + if(!src_fh[0]) { + strncpy(srcname, argv[i], 39); + src_fh[0] = fopen(argv[i], "r"); + } + else if(!run_fh) { + strncpy(runname, argv[i], 39); + if(!(run_fh = fopen(argv[i], "wb"))) { + fatal_error("Can't open RUN file\n"); + } + } + else + fatal_error("Too many options\n"); /* Too many parameters */ + } + } + +/* Input file not explicitly named errors out */ + if(!src_fh[0]) { + printf("Usage: ATFfile [RunFile] /L /E /D /V\r\n"); + printf("/L = Complete List file generated\r\n"); + printf("/S = Include SYMBOLS (only in complete list file)\r\n"); + printf("/E = List file for Errors/warnings only\r\n"); + printf("/D = Process as Dynamic link library\r\n"); + printf("/V = Process as deVice driver\r\n"); + fatal_error("Can't open Template file\n"); /* Can't open ATF file */ + } + +/* Output file not explicitly named defaults to Source.RUN */ + + if(!run_fh) { /* default asm name to SourceName.run */ + strncpy(runname, srcname, 40); + pname=runname; + while ((*pname != '.') && (*pname!= '\0')) pname++; + *pname++ = '.'; + if (filetype == 2) { + *pname++ = 'D'; + *pname++ = 'L'; + *pname++ = 'L'; + } + else if (filetype == 3) { + *pname++ = 'D'; + *pname++ = 'D'; + *pname++ = 'R'; + } + else { + filetype = 1; + *pname++ = 'R'; + *pname++ = 'U'; + *pname++ = 'N'; + } + *pname = '\0'; + if(!(run_fh = fopen(runname, "wb"))) { + fatal_error("Can't open OUTPUT file\n"); /* Can't open RUN file */ + } + } + +/* List file named Source.LIS for fListA and fListE only. */ + + if (fListA | fListE) { + strncpy(lstname, srcname, 40); + pname=lstname; + while ((*pname != '.') && (*pname!= '\0')) pname++; + *pname++ = '.'; + *pname++ = 'L'; + *pname++ = 'I'; + *pname++ = 'S'; + *pname = '\0'; + if(!(lst_fh = fopen(lstname, "w"))) + fatal_error("Can't open list file (source.LIS)\n"); /* Can't open List file */ + } + else + lst_fh = stdout; + +printf("DASM Ver 1.7M (c) R.A. Burgess 1992,1993,1994,1995\r\n\r\n"); + +if (fListA | fListE) + fprintf(lst_fh, "DASM Ver 1.7M (c) R.A. Burgess 1992,1993,1994,1995\r\n\r\n"); + +if (fListA) + fprintf(lst_fh, + "LINE OFFSET ACTION/DATA/CODE SOURCE\r\n\r\n"); + + erc = AllocPage(LSYMBUFMAX/4096, &pLSymBuf); + if (erc) + fatal_error("Can't Allocate buffer 1\n"); + + erc = AllocPage(SYMBUFMAX/4096, &pSymBuf); + if (erc) + fatal_error("Can't Allocate buffer 2\n"); + + erc = AllocPage(MACBUFMAX/4096, &pMacBuf); + if (erc) + fatal_error("Can't Allocate buffer 3\n"); + + erc = AllocPage(FREFBUFMAX/4096, &pRefBuf); + if (erc) + fatal_error("Can't Allocate buffer 4\n"); + + erc = AllocPage(FREFTABMAX/4096, &pfrt); + if (erc) + fatal_error("Can't Allocate buffer 5\n"); + + erc = AllocPage(FIXUPBUFMAX/4096, &pfut); + if (erc) + fatal_error("Can't Allocate buffer 6\n"); + + +pSymNext = pSymBuf; /* Allocate memory - Was SymBuf */ +pLSymNext = pLSymBuf; /* Allocate memory - Was LSymBuf */ +pMacNext = pMacBuf; /* Allocate memory - Was MacBuf */ +pRefNext = pRefBuf; /* Allocate memory - Was RefBuf */ + +pNextAddr = &oNextData; /* default to DataSeg */ + +erc = AllocPage(STMPBUFS/4096, &pcsbuf); +if (erc) + fatal_error("Can't Allocate CS buffer \n"); + +erc = AllocPage(STMPBUFS/4096, &pdsbuf); +if (erc) + fatal_error("Can't Allocate DS buffer \n"); + +ics = 0; /* current index into tmp buffers */ +ids = 0; + +/* We now build a dynamic instruction lookup table which indexes +the first entry of an instruction in the opcode array 'rgINS'. +This is done dynamically because we are still optimizing. +*/ + +/* i is the instruction we are indexing */ +/* j is the position in rgINS */ + +for (i=1; iCo3Mo>B!Fn^5+D#lAQ%XUO9f}52@&^w zCB(H_Yi+HlEe2O`tJT)ERqJ}E(29yORqDLo?{m(*b7$sGguea#fA9bExq)-f_MGQ= z&U2pgob}#W->iC?aPLdS?M#b&O!qJuC)T!Gw?OCA0o_*j%}fB<3@M4 z2cPR`$%_T^{2O!Hf^QD&_J@C-X&C;E!8b$ELH=vI4@b&sq&T5A1b}L7%lnzzJDzI~ zzT46A?&$8e;9G6MciM7@@`d)`EA7G81gtIiwn8>sBik2czn}UJ65ny+R6rv&P%eNr zjKo71uQKQCWfLqb0W^2MiG~ zauV^fD45(p$+ZRFNGMf`w1kAwNMP;Wh>&t9TJ8`3g_xs_{_yJ(Xz_>dlfVprcpU zWa!8W__3)JJ<7J_MCK!o5LzShQ#*@HwB>|?5JE6F!m5R$Oa0+L3Ac0n;U^?8+aJD5 z0!{w#6%shtA6_YeS^n@63C#6}MFf^NWtBLfs>wK%wY~ z{yRizC}lDb>h6Vf#j9cneCkqY7RuxiU}fcrb^y_~f8-^p;mJ@@9247=V4&t$? zuOX%r`YICdAX6!70U=u6HGhYm0Fi;y@xj;pR|`KB{MOujZ5*9faEnGiR|NqK$9wnNbxSTMoT`_Gp7Sm`s9qK^4PIgZ@U-pYfB4q+k?B- zw$1{Es@SrE+*r#lGYdu9gHfH@kYWA->eUg9qVUsV6LNJq6v(p*{oy+)6bI{x!g>W9 zr<-Rk1dUKM=Iq+9rfDlhw@jI)tySiGP%oxr zqo$ER0~tCk;Hu1Lbp~4uX00Qb7x^2qA=#}oXxB;W{aED50^@>PHCv)xsz56WIGEYi z9^4`Pd<&j-!A0AGe{Ty$oZMBJPxV$D5x4)*;4Y_y+8UyTV(G~9nwiK?VSWgQTC}35 zA?Ao6+Aab8wpef*)k}(-U?fszjUQ3}BE1dwJZ*HHdPr$)zb@?RsEBJR1C# zIXnO6-#B$^<|at(TdNsW4{$2S1XQA|WMq-p(^nJoxR_EI#M8XTtj) zm?DDd`^dSl7)+vh$xUZo>eqph2A}yLIw&=QttZWlHnS`Ntj~VR`ow#^n;{WgG(YCq zJ!5+=*(`;&C0H*I>`DdcPaD6Dk6nD2e4u-`2e)IU0E-ZcHfxKZdKk5C0jgu=uF$!( z+9GBEXn%+Hw?|HJ6sS!tU?vraMxZ}bTt5_7@<1(gR!o#W1mJ$uob6?5c)9?9e*_f~upN7JP_o%@*~D)n_`J?yz{t7M6^)L>qi- zgS)C?hc31ekOb#0DARR0m?DB*3V|{aXgOq>gu}!Qtn6xt#SXpEiNFcCoq+5c036*7 zQe{9YJngdeF0?I6*XXa17Wl$|mTUe|!iWA`FoOjeq_B*a!Ck_ds9}VH8{O@|#lkFq z70WmHK-5`B4oq=GQ3s;q6qB(-9}3EIfosu!h*2sh zEqVapfn78yx;D52@=J?-d&JSRws*inST+!rMp&fyuTEf2N}yix*^Sj~(B53pZPg1z zu`P{215@&<#i$FhmVDK?8hd1-)Dut{8j3p3I_7CnL?eSN5UXp)4VWka_%tFz@c?p& zEK`)nVn%hGI9$BL$edEONvvf*XiCS_yqytrmqgtoXSd48w72jP?U)6RdPVQf9N zv@T!u1GaK1#)Q^rO~IwCj_N3^egaMrqcxIJ-6i34|Lx?f^$;t;8jNj-^8`Y7Fex)q z563phi76my>74unbR3-Q2AP0r@778SYo1Q9$@J3+!z~Eig$E>8 z_-82%V=x#ligZ1sWFt1~3Zs=bCKN{eZ6dqa^|7F~(As)silx=+{ z6^j@LqG-w8b?2&+4S(x5uzh#JyjT=2%*T8k6m|&-j+2uV;5GnC8s|O}p6g{y+6o(+ zuLl7P)-Ab280Ol!tZ?gBR&8yBt4={KB{yN~jy*%J8FnIYXI_?G+?lDCRNSVpOkODZBVAwsaBt0Z6xj4Z#@a_t0xXNQ=g9JRZSYPQ>~$Ee zz64)HB9q^!g>HOsokq7k8J*CVndsqK3Y^^fH%dJ?N1{cx>J_1d5iL>mOyK_>@MI+b zVU_tK%+85{1D69Kr#+GL9Kc*ql2cA@Ep}Lrqm^^2GeY9KV!>Sw8Fajd%4Y_5v}bmR z$Yb&p9y!O_2XtbOur1cMQfO7?N55iys?1}t=EH!mwncic4RSZdzcKstAE~9@nIJ}{ zc6M-*lcmKs7O8BFow49f?lO@X%(<|)`d#PsFwn7VK0C%-jwjn^P4GJ`mR|zl&N3hl zb!T89JWD)!t~Jy+3D7FD!cy5}l73h5#} zSCR0^RZLJfhpJXV{OPq1rG8LDwQ^=C<(xu%j)qLsHwV77Fr7*rGrAJg(ZMpOscBfw zZOajMV%gGDXgty|Lr4;cW%FrE%Lm153&vauVZjo^;>B8OA(~rd-ubmysa77bFeMZ{ z%Q<^u(&#PNmQmZ@aj1ZrD~Od6bE6lbHXr*?CBM{L`v2?*ez~^g8)Xyn9^;0W+E;&U zB!ZcnxTaD7VvDU^c8>6ljK?^ZYT#J#OWKz>uC`zvI%DfKFg6{*f5xW%bA0ei{|)xG zRKrLNT;>H|VyEk`0`euhE+9HQa`C_-~v6f)&_25eGf4?5vw(nLwo+VgPJ+eBlfbN8%OZ2$S{S{Hf z_5ZH$8D{YibQ}dSL_-t;!W@cpHt_^ZtuW+ikfSsR$6T`)KqA}(z?NSdR1lj0FJN8~ z>Bd9D=V*9Q(3afJ5Lju?F<%}Gu$$swSsJVi$U46OTd{0DG571d2qhk4@tu*5_cr#e z=YZK!mfxN!IbB}^Ox5Od)@B(I7se51?k?h*QErI2{9P}I4<_Qz$exmwH5cRwTq4Kl z&X}eMW23vJaQ#Rium1+~l7_>~&v#&uKVMqpFl{WPMGga^u1Ww#C|iM$XeZM)5`&um znO9*Ljc|usb8>{P;z>wym`)<4{Ae99{gX)&qBMc+IU6`%RuwBII%&iV^J&cR(TJRR ziA-%1h)p+5&Dz9gOPM(+OC7oP-`3_3ZAE`YnFCku&ckr(nyKvG0Hil$nrA8^oIDF% zBB-$uI7o7D#k>gJJFb31^~p^?6xIxl&`G(Zij$SA;0ryn5{|lp zX$1*LdkuCwayqbs9)Y}q@scBSNoc!a?rW7iO_wAqR!MGjC{e2#Q;?A+04CS!kc3(t zom#8mNws*-mIifjMw37ylwURf;S)-xfKsRV@OZ@Zh;r#tr8UCS4vQb-z7mIev<@+_~jB5;+IHJh+izh z-6wv9zzgw9B`Cy05)|UABq+q$NBv=WP>+#~Qp{7wl9 z@h%Ap@wE~Z;++x{;x|f=#3K)<6R?xa4FWG@u9u*YxlV#Y=2{5~nQJ5{WUiK=3z>p; z=E!z$YXCtsZ9zvoNlXipF0+#28c=YrmF91?!0xk>Y_PmdA7pmC1+1ZNU*^*rFNT$q znPpDor!Wji#{zld9Z+}-sl4FO8aEdYVhJC)2ahDEP_#gs!#M24ggxI4_T&`UnS`x$ zgDp&f9ZJ}Ny9fI{*oo{+tyL&ml!Es)!oKJRTbu%WH(~E^gVp@D9tW|f2uTxdW}MJ{#2sY$!5zC|!zhaeH1+!G?#4yF;gQ#ma~@b6=QkGzFPiU_Q3 zJPH+0$*k6hIB7xV#z&>cVCnrBTF4l}(c(tJ>ce|TA|r*wk4R!4HxgDY zrn%L^qVFn5-9Oz0Y1Kd8T-RgH6}bYBw6ZEskrfnFWQ9iNh+U&fy9iSQ918#?(;;qz ztm^EhZT&b49RC%Mv>bD@J+XBa#~2ZljnfT8cBLD#nzX87RX;AoX~Z(w4T~l4iC_sc z*q5Pij};3>Ic}(Ws^G-H3E)!S0TP(*4_~v3Sv9!S zCxL2z_@6j+3Pq>kMzaK}{Na1PWlE(#JYE77{_r3E#gwW3@Yxc;rSH8YFvTBU6J^$9 zTt}9`BwRAw$&`uy@U0S<;1AE2K$$;$tOSDo@H`xghN7i7l9fOS?p$MAITS6%4QmM$ zfw}|=fms5l05i6XLeZ0fSpo&XECC4k1Oy^$APxK25zQEp4JEXK5h><_EAvnkESiw3 zu=u_Nz~UPc0Qr|C0P@dB0OX%QAkvKoQOgaLSau%zXD1({yVvE?+p?x#Z}@#-o{k5V z*qB&Qbq*F((V`P(#v@!C&j-1a(CN}U{W-%iN=}0Xj<8@>@ zBU5x_0wZVX$T&uRrX#}{xkyI>jNGmx`!e#hj^r@%jE?+^tzhcNHb!!AZIbM~&qyyF zd5w`VI`S+dRXW1$$_>kPof!N}p*VkOZAMoM+$ z3`Wk-kt#+m)R7WKF4vKZEK5`YzYOaib%T@rv9SStaTffW*f8K{*2tk4t*zzU6#0Ibk337q5)50t=ofA}B? zjPr;0mcWVraIOSS@Q1&IkqSkR_lN%?fwBJZa}pTi4?iS<<6wa$Fxnr!N&?6F!{fB0Mp^!0~l zOQ4TGTrPp${_t1{KN zfq%@&8Ri2RfkMyh*D+@32o5j2>ao5r?6YIgv3Jom&S45C zE^(@nV1b~(mCxjY`Z_^q+X$Yu%AJ=l^&44HMG#9mTwJX(KYLqkjvoP*aM+2%)3q&s zLi=o&ylcLc9>Xb>}ngfJ&6W505qak3S zQ3MeAdUj_+^wuX;q}h;V-hw#~7IJ?^3@sJ>2IBd~Vjg0ow5rSvm|Jl7od-QkkrV8r zHz7Y#sgpwX3lTQZsmM}5Lv0}I4xA0dsfGf=P>Yq6h8!P^>bD|<&usH6%)7wnaO7h* zpGP}$F;2;kHIDzI4$DQOK>}p;aV{^Yd2nv zjLhvb8+w^_Z#mA?T2)JI4|Sgzfd;WQ+z(QB4Om$e#~v?lGGQ}JVtjRNN8|!jDB;5U z0aBx0i8Xo{W!47&Zq=w9q@_lGch=|+07|aW3L)lJqrbC8at~o=WMegE1FTh!dBvNq zwesy*t1LFz%c&th-f%E|6jk9$})Y zMCYMuPAeK>UE-f7OzgsYT1eK1>Gn~2Zv0~7iE#=kfU)JG?XUcq!??8`=X@TJa(Ecw zD*_H(b7S~Rlul;&fZb)-I->tUh83V@_|QFMSdT5G0jw`jJDm99UA@pVxw0Xp+I4(3 zdDgq6G{L%695S<6a7oKGxBiJ@uv@~en6n`@AE$zk^yu@|z_;W%vY4NWGAHx_#$qhQ ztd-d^pi|X4Ny^}kVlo>jgMr*p=6t(MZVzQJWpI?a*e>%YynzkzxzfRO#Zji+F0-zO zGMI8X%3NueY3!j4rm>DPH`--RNLyymDueqMj#BIFQW@z>$;Q32)V+48m$0yQm%|_f zDwII$A-mM|X-kDZzy!>}-v+zPY*j`pP`8~v*~W$2sFC9^H`C*s>Zuz3X&e3^1)re! zv@Sg=zPg};zUOFgD=pXj5^rLrWOS4zSTN1UpTS3};#;V+;;+C_Yog*SfQ}T!|H7_T ziIj0FWV}qG;z#W={vOICDt^o^^DgFxi47j7lc@MP1FTMYPY-1h6~CWdW@!&)5*2@c zyUZzR%M4m&Bq`&ecB$U!OQk6OAiLD-o6^Z4Rq==0rEW`GDp~Qz*ku-|GFpMg+v(G6 zTsxb0;nc zq{(zK`!!(3q5a8Z`lMotEzeL3sX5rQ<3b9ry`h_*gh5$%^ZIK>>T78AVX$r1fg^R# ztUpes)OET;7~-v$t^h-qGIRt(9SjX&h<9kZh9M+|Vg3G)jlLb9g#!piIqR<{a;3z||Ygo_&Q z)i{|I95=ogi=Ez<5xI+OKpqvT_IVC4vf5|zZAi8YjQAP_*lx@Tv4G=_r!_5w z0mt|@Gfgh;e+GBe&pt+~$xY_I6L^UwHr8AQQAkEiB(F66B_wVjbQjm(k!LaVZGigd z+8pAnO^K5^kq?BT0l$I-L|Cza9XR2|HcU)8Rm?| zH5Ruf9h(H)mQc4R9c?N7PIV!<&&E$kI1AwtqosA^=Lj%hCxoJd9hVKEBL(c4dPE;Y zNHH6>t~v1vGZB8<#?~>5P8==wa+2-?b>#F=i%|F*f!|>bg1QagGalJhJJFmL$%{TK3T->t{0xU>^14bOY}wcL}eGo99xP zzZ_fDX_wYc68I97IA(O;>+C;kA~?MSXXBVEzDO9f{PmQ>2p@;xPqz_X9+ zmQ;W{E)^3~BzKutCSjlNj$Nd}DO^LY`TpM^p)nY792hyx&|Rhm7!&R0zOFbm_~`&w z`zhOg!;0Y@umtlOc@efZF22^Efs#An#uUOg3&u1Cd#O!$sViY+Y>S}2qGw&j2+1~G zLvQmhA3y}hCNLJ>lE~QLxI|iQO1)hvnZ^#(JZin^vkWCwx3M>Nm_Jo~admz|$^wYc3YSFW{7Jd5=+ciat zzQ8+paV?q#M4dlD+h%6VvYJ7M0dVO5>!LQy*ZME$le@p_!voF!e+AQG()yWs49^Ck zhP_OKVcN4$bh$q~6wMThF2l@FX0?m(SF?)^C}0rawFj z0trRW_J?0VgYt|nT*Q{Woo%j8#_)lL$YUT9xfDu@SGvX8;Oh>rf8gJ^S6{rP8djQGqha+71A$vCkj?c@Q+MYub%vZ z!OJ9dJ%cw&@CF8Nl_1wW1(!&0HG^RZE@$vs3CexC4hc?R>OB%XiNQN0IEulWBzPo) zS4r?-2CtDIuUr(Yk>EB4*GiE0FZ9bzZ!mbdr1CO`zP;DYpn5;%AqLw8;4TI`C3rJ~ zH%sse1}~Oin8DQ&T!~<02pF+H8`ZeB*GJ*B^o5=0yG5hhyS7;%zL= zB%8}{XZDxO&PTRv-z1vTDsx}#fc9X<5)5yAQwS!LdqwJ_lR+?{7TI9a)wm*84*ZcT zB?J1fR@6MWi-)||Ks#b%o}9v$toe!IXrvaIc8Ls4VM1~Ved?DpXccnw&Y8S?n2Eit1l$%RanlGYtqkTq z#>v#qNT}P`_%vh^}d4lI(rY}1xZP|&c?9%jQuTNW+OCHeW6_hkQ zSL^!jr$8KXE|aoa_SQvfM_b{RwQ4QCG#xn}BVi(mUze*^4nB8b}Wny9k;qUsZEypjnDYsuWI>3{18@M3+M2whm28p^L9W zsih2ot#8{owA&I%*GD$wXN3GVLjxpw4TJT1#Q(l2>Ffq`q39^x;Qhd_PMW4# zS8lQBB!f9B=UyB8Bg%r0QD%a-eUis&KMo>{b&*-UO`XVNNQi^R*rlV`4Ka z;=4yfTLed!triZUtoExoeK)OVI1R!#BJuL z^Gj-Yf!u1t$OD*u#bxe*uv_qrjcVXNLfK&_E?iVhL>G!$ALl^humPm6v0-3NTDhC) zOoQ+f`(FzAj-0O7fGLSVNGh4EwP(e}RXS*EfRP_mu=vo*K|Uh7v4v-?9Foq)w&1mL zNcwR|Z`j*B6^G%{P0`~b0i^MsX&Af9=-fE@{J8|sr`y@sT%5{VJq`PqhdB#!Kx)|6 z?BhrirO2dG$Wl{FlYR#341znVU{3 z&`U$z5x=!N;>&=6Uj8@6STL@qTVXPjr0uF>SgM{pmm2ni1rn!e9l@_%CO?m0Wnx!Y zS)QYmad6Zx08&&_b|jz~r0x~9Dh9x%{#wO`Q;^c0^Z#X~A}i2c+#BQc6!wzm91as@ z3wd{B#zW>rniLEbk3$l293rW)L?V``5V4;6q0NSxuza08)D}&q(1Zd4Bhw z%3&pT3$^Z8^Usvd(w-u#0QmWTRGB!L{r^wH9+kFX-PGVEG=wx(!3LC5lZ;l{c$N5j zJ2CvA!t3b&mU>^Ia{ixE?;TbZ_*)=qZR}VoSql($!^Do6Yz(+xV|TyZu>$8Sl+HO+ zlEG#twuYucK-)e4ztOKTq2Nuz@d-OiZarC<5^K`$0ukT081zF`3Pr8$i~az$>K2IC zO|HXO>4ouh&FxxD(J;&9SgHo;1I?ed1!{S8C|Br*3XU{p`aao1KkP@%Uuj>)-MyMADMYh zF0X~DOt38fHTs?rZuhpL_<6eIp7{%-VKSp0I zBHY^FN&nj9Ver3J|3KRMcRTCvLcetYiY6%KV})^KG%i|`i=CKW07yf?JO*j{wnd+T zDLqITLbWipZo1XtcmxOTx^ISnCKSaFJMmC16kX^K{}rc2p=cA{u$2IQ!cV;(Jl`KK zmOYj8aj#I0N6+$yM@j&91`m+{ZW`uF0GAN?gJ_{BE+Jkc0qn&5MUGIhNmC?O2{3PZ z1E;}}v0T0_L`bi@!@a;0*6Am~LlRfs@>4x}+|c_ijx{?^I~oR<1D}-TJq?lQ8%|Z8 z(!U*&)%hsKr);CpFve#;fuR0{I_^N$?+v+`2(_NC`1}Psc#vvX# zP9gv?wU_njB$>=?vf0I;K*r>*KII}m07E4C1>KN=-s@l=>KqP~v1~pg4TvkCr;>n1 z2@s$1El>sYbP~`Q0pc?furY0l196htd7=RE*?ANm1(Wtk6#wZI|82j6pqc#`8b@9! z=!Ih-zSD;qKnyNf_!x3KTEI020?L-0ST^(Z*=Xk=(!UZt)Y<&aq<<*rV>Goc0tU!9 zp*1@jpQNz2tFOtHWk(K9lh6AsB%NAR8qMdD!5ZeFhAa}x=F@&%8|QA=#}HL#7cnxy z=+)Tb(w9nO%G7X@Xm=UzY|2k5QM09FWD6`ZI@?pqFgu4|WjxfLmAv5~`=Y53df!Vv zW4c7p;PqSUXS9{ldSxjXDAALexC$j&tb=q0(*Xg1TYF* zE&>*l~{xJs2`hm4JayFdz^idOebTg@MOu z@?iiVqm2h)dB*K|bQJ&=R6~;bFhm_^VDmOJgf&O}^Pl7KL%-@af*yz_LzL<_*UYDJ z&xLBjZDJ(hvpT=hDeO^9$uRHGDV!03r2O26=J7nTYnk8BwmzNDU}-{p$AB$~@QRVz z{^9Nbj>GsNAwmRHl$X=x{dj#ty}_?WfAbZzVf}UhnQz_!!ElFM5UOh@f>JFrNz(Bh z)o_tQY|(+aBiUp+^m0X2H;V5 zM;}@Ptw^~^26Oy4Y9g}Wmd_c9Tue~W#?n`Q5Dv`jVc|-yMX0 z4Q6%q*4uwC9Nw;>%}DQT|1Me1wsj5n@xfaNSb|s&}fScL@H2qyS34QCV;zl$>=kGvE#xS2_4C8nCl+7ZrS~C)dM%%RsWS;_2DxU<#FZ^2a=iZ2=tu5bbRb3Qk;Wsu5r9H9m2wFdq z^bQRN0E{oqlX@QWe0x;y*9<2LLauCVU?;0UUDPyOI8T!If$ zwXisJ?*}h@!8Vh|=yxr;xvemXidViHif6&}q<9)8?9#rLz#Z*sHF?Z#-?cZ|D)xI@ zbaO9u6SJ<>pRa=`N}*!usy10y?Lq38UH!y9Wx=dTfJy9A7R9#ON{JEx_gKi(S4m}YT5O+AiHfr9=y5-LC%06WFcYavje6|O5wLZdsFxy>^TyjYZuf$W=8#48X^3Lbb4$k`=LmEa1^nM#o z29}P00FFIKy~5U=)v;Nmdh{lNgV3$1_H9yH4H4;V#}yEMoS<46z=GSXsuYJwdCnHe zxfi*K#A#Bt*s$fUu)1IT_)2GUCaS6Rdk04;%dE%x)`{`@`x5Ifvf%lJe4b0)ouiyX z(bf724yO$bgU#t!M#-hPhAcf~kJ?5%nk>aT9a8)OP5${cdnnA8YylnpvmX-XA8gpz zg>JA~m?z=_Q@n2^3iA}*H@a1oEIql!QNtch-p#0=?isJy+??aejn(%Z_+n$&S@f87 zAi9i3^(PzEk*=t8#cqI>C=}*D*UBHJkDz4b;Jgb)@%U)3OwTd`Mjss*pr|PnM zCKZ!g7x=isZTG0X0ajrnuMWn>))Nw6J^SoMoB>eO`i2Ien=~{Rf+~we_>~4J#EIvx zPzvot9FKJa46`D+5-3GEWlD0ypDP$o9Hh55-XBD56Dq4bywHD+qRvIPy8niD^KX8;u~rZ3K91 zZ+MhB^0@d%jB_T$_&Nt-9JvwW0uC`wV-e$I3?ARjg124e@g*vN{7XE1cj*&l@UNw0 zSfyAtpHLc!=rBD^IU8lL1Ky-jOiM&z<|F`*CUAyXtbvb60)G29 ziVqS00Q1yNi2rQ}QFvm{TaE(M)yc0az%wlb@v|l_bHUFL4KX4Pk)dXra*PZnaukHz zqm-6_wno@ut`X}DnjI?=1emlNUOs$GTQK>hy~wTTA+~|EK10lPfDO*USziC;Z(!J< z)^A@VfU>svn|D#8ip+YYVR;x0B7B{MKIR1MES& zBf24d8EjxDl(DNcCw-YfQW;xf(w6SL72#U@8W|&e*>-E7ssbsv& z?pHEiX7?)@FO#;CN20cNOIklklOPXEhE9`{qP+aLnbU@GAh&e*P>@J2Y$1)jgJw-G zXlb-tL0bztT?$(I-DAOemx7kIyA`yRegq0?yB1gaZKzzr>!k6|P(tZ@#P>k@qEHLB zqITuEahirIw8O2aE%34Fi$X~_K}c>ZyF(nKI)r*x*Xj@{0*EW!9t$8|bdLoPFS^G9 zh!_1K0St$9Yz?qFi<`(SY3p0nE3`2ssMr}1F>dMDzj)S$T_Vm4Vq-XZn&12I7W%FA#XFlcvG)XS8Ab~(T?J&MjSr@@ zxUQg?<8qu+rK8RJxidc;x@A#HTCpeYaZJ}!w!}Tl#646EBfmS0xe90Ok>|+|e{|8g z#@OTa$9cdaji;^ygrfWDO(#w(xAL>MxNo=h6Zo=3F!W4aPlCBbuzuXBRi*=249k0F zz@v8JWd1VTyaAif5$+BGlj5JdTDmUg$NzLpmIIvheXN%O34GVt$cy}hQJNMNEoYPptfB>sa-F22+-`{AN(9FJx&H7+V4wH3^_x}m z{NZ0q%4~m_XH${a@DNI1AUqDU;W$5XZ&+P+31W)7o@~k-%G~RI&Z@WLyY7*zdb84~ zQ71W#Tiv(80By~`eRq0*3NObqV!|*}mRA&imG$=-5!oXx1SMcJRK4=w6B!8a)Gv<$3 zm(|3^5BuOsnpTxv=I8fP=jt@ylK_I(!ST&M(KGY}^A!N-3J=jx2Lj6c9%pm5gnohk zq`vSo!W@bNfyn*@ISxgEO?}H2J&!Wd(zo7b{1R~B?=xyNyOi#0wxU%bP4jGO?Rbp6 z$v!_c^$zK9G`iN5f7qImRqv){>cd@T%lY7Q5pe0Me(KQgDZ+}&SpdbSDTd+{Kes7f zJ--Kvb?1^IRLWLCr7dq|iV)aHVZ9cxIvN+yKdf$J0HrJc1z3r-?9d-4<7C79eja(s zPyX5)YGM`2I3lIc7S}@fQeSN94)R%o5$1;(>jx;u#zUC3u}*d5{NEQF!zHlU_YH{V zY-D!?KcH4wnf!Q~`TXn1EK!;A?iUBx`ls=TjUfORqEGw@Fh90na3_bGF!fI*z}!F> zjyX0D?7F;zAUs_9XR2$QymdEWqAU4Lg4(*3aFQ$e?gW_rfYG}5ljY##m*3;@CM4ug zyjGO>VX+=7c;)Bo_F>aGzC^co9UD94OI)05X$?6jsl@wp-Aep06TFYITWvdnvN;w2djbSyYi6Oz&~;2p&JC_ zS5uA$jBeobmVw^IkdW@`mPLOY1++a5&qmnM^p5^GAhkc9ILECM$NOWxa6ztE^ZR#$^T|n^2YTZCbRy)= z17!XQ&6dmvMw*x4LTx098fn}AN#s)zReWw_4NzIC+Mlv8HA)vy^FcMi7-b$$boU`Q za)$yJT74{VH5=ocpkcJx7qHd@Z8?(oU8gWM_%RCOe(y>N;HK^r31H3FxRY79d^<-1 zxQ=_e1aM_{ngoXU!xJTdE4!yi02g$}N?-|o1XKd}A+*eIz~cqfipRco%y)A-d(~q& zm04fMTb-GRWE+KeG2?0HOBvH3bo1`ZFcaXf$rSJhXq~t67c%=&WXHx3oBDeC7)~V3 z2Nvr>);5-!!pOJ$+skqVUt$(FXkC(p&-SuBw=B08HL_d)fx0XoHtS$if(<$V@^=C2 z$mzEVIk+~?i^c8${2df|srwL(s|Qf%pMYBX@0?}Dx!_M^x)IUuFXX$@4{go>d!@UF zh=UZrgT}T?lr>gwn|%;>TnD-s6v&wTau6qExVeQbS@W6OVCk&&^ zA9q0A4uGW0HoI(Om2}7C!-ySg0J>GO$5ue5>itP;e;j5P<6@q>CqUFbmlD9|(< zZ~g<#Qr7H5FN6bbcWw21bWh z1wzpU_ytP|U?qB>1h5kQ7;}_R6f4nRNdPO+pGm-npYuf^!dqSG+GEfvG9laXqD8R5 z@`@|#V_va6!3a5jRl#ac{gW#q&qDL{Hjv|wkviraobM(4AcIvDp8-JscC<&(yoTlP zO(?JOdqCn#Mp8i}bAZH^YCmNZT=NE91W6@Wfq*;nR<~ELEv3pu?lGY^J38jk*d4HT zPbJULeM3WmC!Lum_CarZos}pqyQn;iYNBU z1JZ*zyX5EYvZ1+h_Q%Zti*u}+GhKhY1}pl=z3K5fJL3|7p);P%B6AUrFdW6HdZCi6Ziuj=FhM*ARqB8 z$ORtfJmF4epM~t$7-DnI6Zpof6tV^=wexS!6ApEZT`EiF38~4#C+7(+S+4U0hk(aH zUT)>MQsDraijo@1k(euRmu#!Ex@1{HZ(OWh3<_i{o0J?qe9{e8FO7do>}ZhGqg~43 z{wVX#5ZeD`cF%rx*+?Pcj_T?jzLKEpB`cwa*D`$#Q9SZKLO8`%+&P9``*$T;ggclCQO2D^Xk5w)|oF9xK!_+FHmi%{go1WHz4pH7^m z$V%+%&q#+xUq4#{=2?Rc1wfEVeedy$Zjb`|^B{Ou^@X zJshw-0ANcwaz%Q2{EU2+`5k(GDh|c8wQQaYB$}t0uHeFx!gqhq0J6=UETUKsKZZ68 zlUVfG5DwBHcQVqCQ6l~iI&V!2;Znzzrkj6jc;poZ0;z@KN`RGy93*IW)1`! zc@q7|QA`(7lCjRqs$6N6g(fO1v)RVp~!X!PeZ$tK6-}EFn zPINc)?Rsn*Mjq{LqXnDB;7MYcD1 zz%OX4&o6Y8@h83=#=w%fUe>*<6+59&V*gzv{dZU5XB|4qvaONoPE=fv3Ih>j%@eRW zKv(vd&vB|FEipB$OvebHLLqUKV&BmGJam=|wD6;_<+x$9^Ys{&P? z(d;J_w{eHM6RrNeXF_`>>7JiZB(ZWyMt^sd9DPeVV>g)9Mt{F2dQx)qUNQQPQR1V= zm6H3&=6b1hQY$CwOp?vt9X2hS;pmHtKsDLsTlyOxn;d=dB+X_4*}MR3t_{A7pIc9A zAo;1`l(by)($lCdNg4d9;g*+qVYMwsAKiS0{!PT{M^}!-9x;!4y48>4W#^$!ck%%> zWk;W}YY#el?~UK%9B#uZu-=xV!q5qFXgW7}Nbp*eQ zO_i@yRii9osUIoIDIi)sSs&~Q)$tsr~*k3@`L*-^6LdIstCbSihl&Cq-KW#6iXx%LmF zsvlg%YiI+es!KH|X22qGw~FE!0YjV$I=39kC_lR@dEC)gyCT!UtNA8gkHy(?A1z@X zMVcE|;mweTv8f}wMqS)u>f}D2>^tFV6Te<2UuKg}lp&#j2~S`}C_k6uII0F?)@_2Z zu$@mLif!Ohv9)@rnnat*8YKVN>=-8U*G2K8-cll8m#DKbO;woeI$K{~qcC`_BPk=c zSBEVl?EL%a=f-ICO%9-1#!U-vL`% z50+wMm>wIGkEde0yhM+?a!ZNVYI-BD?z{DK`F~H0I>g(p?=b z@Ymosy(d(tH#qtM0*Uw`J^V7yd(bTnL7`*X!8|q7vVI)O?@a8YZ_@>sDANz&LVhz! zkg{xBX5=0sRv$g15+R74KMjg&grR6aYjI!Xs-I7i56S~jL$P8S133^~UcVn2z~1(qO0i~lVK6sqF;Rl7s69;Mv;~tYQKr{v@hxFndKkYsd76OQx7AoB z-Tsf;t#?t8vtPW7bV1ldznCf|aKd9F<~>o3m|urT;>h}zjqjN6rWaPUnE2Ls$W=nq?` zmY@8BnKF!G1TXstqz*@&FyH2{7&x-FLF?5e#uBrR9DM-8t2k0JbmQpXDI8sKimOa6 zxhM@s{Xb31(diD3US9|>%*4~QO%`4~No<>5u6&5t_kkeP$ah--SV;LKTI5Nf z*RcBmww`8Lt=t-=09I~-owOa6<3Jm4P~nYKeCL=#^jDY5dHGLt6Pq%)OU19`-6~h6 ze+w1anj4c;UY*~8IaEhWuJzHqmR(|IM`*?8DM?2Qmy7tpd&!HOjwGe^yo4J0xgF(X zB65oz<)A0cDGaUWiZF5^bFmv_s3=cX>JLJF%m(gfpM|LW)aTm}Oei|jAAVH=P=XB- zDD{VbDS48hnpX0{9f}3<;F`!<-96uI7U)5*Zac_=a$6Avxgh z+&csj8;kE*?1%AE!M#_LkXJvH{Dxsx@cZ_WIVj)B1ptwi6WKUS;1UV|+4EQ`CZyF5 zBa%~qq{}MI{#HMN$!9{F)$h@lGFr)KIrQ4WHZO+N&qS_Luy@8$!LsTvv{N?glukS4 zw>ss|cFLVPC1$5wty7M~qDNs~rBlj~Vm^zL6T7m!6(f}u@!^f|4<};g$lBAcwnRmZ zj?u%uAN;Dc(Od9JhI)55VMg%+8V3-VUZ{`ladJYHiT}hByOxG1MG&LB0;klIB9UgK z*$6EAo(@3*HZBVBldq%TDJ3Tpnv%-Xkr__16;_0^4<(heDX}wP`Vw1s4wEmyZaUaw z|8Y(a9|4y7*^rXO}&&Ie|X&JcMKr~91HXy!v4h+#;nW%xb z$Aa6peuPYyZ@2Ey;|yOJQ5Mqr1Z;3Su1#?25qX?;`${~_v#{vm(O^SR20VNhJJN*U z!^agJkOSA zy*zo<$}rBA=PG%&$@5Bi-YCy?^1N4`56N?bJiFz&S)Q-T^DTLPAWu`C+vORRC-19) ze|hH1v%fq8^5oH@Ver7)FiwzXp*$zbvr3+`*cvbp6AMQl|0+zd8IsWl;=8m z-Yd_ClUkCC{_vSuf8e@;q0btK``x&nxA5qdeEiv#5O11e&Mf)20W>M@eO=_@zbDix@90 z<`X^#Ao^w6pHZdaeCG>)rKeU_6C_xn0E5#w_8>lMdNuKv6>(sKui++Dl$6f^sfwbh zLa!pI04mGMYJ$_zGm5H(e${kUu4+bc`J@uVr~zEbMEDacs{v-zOfM>#qI`+Zs0ohZ z`^@l19}9oxr0VH2ipmX5)+j<*M2(_Zs58RF2p6L&#fTGc3F0NyBjHBD9Sb+wD8Z0Z zg8WkCmtrg`1xzVmN&!;}m{P!$R*!`{-Y5lZDPV&j5Cq~N5C>5>h=M_61Z&^}CRkHt zl);|>ha>}0qXyyWz%w0qcK5HSNW@fBBw{Zrn#zJjMZg5F6au5C@>I(dRab$1qquSg zKv#0ADt@Y{Ua6{4sj5S1P_UFvnn~2bis?acI!=twk&-48og< zlI2uWc+^sO6G|zia_TF*Nh(&Zys0AA@=EE6<&}bs9%@JrVxg zbn(Dkd5zSzoSgwNrGrx|rTO78l^#&j18RCeO%MGJ-s$v2C5(!o2(m(`8Wok&?v=`- zRL)Sb8KSL-5hp$1qz9Z;svJBDh92_ZQFQben^6O+ARb^C0}MUDh*xS<)20~kgl=_E zS_d9m2OgW89_kK{&7%~O9tpvtW>;4#EQ(E1-9{8k( z8o{=*D)c}W9!t4^@YK6*a9< z+FGNuwMH4an(2hVFe0X_W_qQdhQ}Jgqv+sKbV?O#W>93t^k5CuXJ)XPl;8ovIJIaJ z6K9o7r08aq7fB2rip)|CS9a{Isa&^}6%~^bd}W>Kv#Mpq%9fTD*GSdNN+v3}lJX$* z+9)fj6cbNh;OQfPxPpVhWXUpZG3g5&d~(WoHQ~#ugAl1vHc2s1Hc25CpZVIjijRV2 zlQdu2+Lpo23Y|$6Qs=TsA`if6z9%U`AwHv+Ik+@a4VD65$!^N=zn4#b5leN|5- z9>z%?zS1Z9QV;q|IdAVne_kE$Cphh>}TX=Pn(Q=jeK8r72>P%duLanQ|B9b*(D&p zkI^S*8fIM~!>j*=u6`eS5>py3sKB4Ur7^ z`@%P(6b1fv83ykF8Q&Vl0q}e|hH)U{UmHe$sox2{{;c0gMs9zp-wD0@vwq`@KK)t0 z6O6or2!FR>@I5)>9>d_9cDe8mrGFDe3cB!r4Br?`k>GEHVGN*onrP$?06OFQ+}?-N z|7K+Gf#qnQ&Bm%D5H)rf#vn;Qq4$yE59xg*<@QS>1O8-VA$`CvG%iMbs|`IH&h7!AEi9Wy3fIp7DyX zY~=m{D=x<2k1Bw_0zTyLyVNj_Wqc`o#zWXzV!RnX;};voaf~mA&-f*VF-GT)(fMN; z{|J*>`oLSnbl@#y9C!;E2i{^GFV^vs83*2z83*1|7zf=`7zf=G7zf_t=`VxN^sr%^ z$oNI@8NUKe%J_xw8DEQjsN-ciKAv&hof^;hWtg$*cu>brV*F=N6~-^eT0zH4b-aY} z7R-qmZ^in6anPT@IOtDg{2cg2CpF0sGtE5tsfp#D`vP7G>p0Q|7IBTwO>d71H+i7{d)45X=F4A{{Fs&Tr{jRau;&4v>tvTI>JLn z{zCSv4e;6j*BE^kvj4Xkc?)S5orFM#-jV#9Yh;}Z?v z0K_LEK9KQAhVKZ(Cn0{Mk+BGD8Fw1SV)}O(MiabT_)Cf_4d0W-#Y;*n4BtlM;&T{( z6h7m>H7;%jJH|JG-b=;r-y2P47*|3yB%a@Ux!AE>-*VcqJR^6x*s;MxW)Z zN3M~#g3F#yjocMC!T+a`3sn03>_RYv~mDexN%V>Q?| z>fx`2zZZPshp}Ewx`)9h-5mI&w+=q(-D?==`l1{m?T6{#Y8b8BzoZHp`D%XqB~?)N z*XX02yYt&GmGu7bnNFYS{oAjUbOS!q=`-DEze>_`;WM2+({tMqGmNjWJ*@pT^uMI& z@b@(Qa`;bCRq*#Be8yiejB5m6p#2)bN1ylt?bk~B3GhjWKGRQVe@w$arr{sc@J~qk zkoG4eoj&1*v|lIs(BF3*_2CdB_d3ys{=KiGJ{)B9xsLkK-^jaxd_Ac5B!6ib7)6X+ z_%~NTzBd?!x6r@FD7=;a)kfiM^shGxZ`biV=wE9TuA_g4QP@fUHluJo{acN~F8a3{ zg?G|Nxx45C&)xKa_a6G7bFYryNB=sb@aObV?tc2f^8kI|{RMr{d6529M&U2%-(nO# zME@qE@K^Lv{$cu88il{6f3s2e8|^FER37CZ0=-KCiG};_na2 zGhP+GM*3bQ-Q$ehSB0;UyYpE;O=@ zUWoTad|$)|7==cWvC0_eD>X_m&nszBMeo0FFE|}Z+ zAL%>eq@Ng1%umcEeJ3>OC&n*HipMGU5MqNn{&X}c)d8?a!G3+pu%s&wU}aueJuJ|; zU~yewP~+Ud@W7y@{rVU`kUeN_AlTg8)C^DrPpxfUykPNsmYcMAd2Qo@xq-TKmo(Qc zUAmxY@vy+)qXsixH)mPhTvq@TX{n2Y%uI*|YUeGhYYwz5u5Df!7(9HiF}_H0IRTHrIk`b6~;ZKrMl0*EJh679(ZR zg2lC9C$Mx`GdM?DbKRV#`HL5vhcvsGji{(`!TiOG>J~2xEJZaI%v*qp)GVuQUKW_s zvbm(uPZ?~~IMS?^4GbB2?69H74I6sGQSm0SIA0ns zu++wElVb}ms$0~A25w4XEh)Kj-n^xC%L29_o0}E|=GHE&wIx|mhYHLM%tpH}tXsAe z4LiHGv3BtsXPPA%O)Ibztsbad22GgVvaAk=B8wL;Zd$Q8u&ile-C{PA1z6kMT)Q$} zIi0*T0QT$7UDjOd&>Xvx@s2<+OHWk;SE|a|nh)K8DC$&uVX>n7lC6)#07a;4UXJRl zXlfQs(_9$Ub&a*l7A&s|G_)*Q5@>2!7HFD>{;+s{ong_Dieh^=uEoT-V9}CBD)gkq z=nO4$mZ8roRdc9Rf{Y!2an@BYMW>&K4(KGfG%&Ym@nE!B?Xo%b#;MIsP-x9_VA;wg z=ndo{P8)p8X=+Ayq^>uklmH~@L5*}kn$lu)=%(gc)H$dPPGInm!P*h4Vc2gG( zj72g?jSCE#s|G5B8WGe3Rl*2n4`7<1n$xBhSC-d|3t()jfH+WeX+Zw8DH$~KgvMEc z08TH16X4Ny!s9tFJRXNKQTuW#i@2QD!pCVXQQ-uGr>+5GYEembCE}okQyvViKTMsp z|BJ*)x~#JL)FSX*9V`o02P;Z~HTZt4Tiq!}k}roQP`G`t(^FE*zKZ_2IH1p-FVLpc|C-@B{wGC|RV}%Aj?;ks`as_j{sfh3ouPpt5@@z`$4WTL2&fG0>qe98 z;~Hlj#U_DoHKwE=tJC2J3~l^egr;*+C6!MI0A*GbFo`e(^*_KpROrKOS zV^YP0;U@$0us}J-m2rcJ691uF?z8x`8O1FN8s~CKTHUf(3R=l&U<>^Gy2Y3^V{%ED z8o*%4YHUHXXd@pOB9jp|vsJj!Dtr{n1W_iAj?)Jv{1NEdvV4-+3?WMaS=HP$hjaeg zrGe6w7|1b%V~w^D56o?wR}ySyBG}xznG0YU<~Cyz*o=IKDW6`4>VS7Gn?#x66u)Z5 zbSukQ%;rBZWT}|TW6CGh9M#9brIV?FnJ{6ajyZm6V91=K0@cS99TO;SX`WA(N1b@$ zvBU5f&Bt+kjOo`04E=}2$|qG|EY@=^1aMwAsj^}OuU?JdJ*)(CVnu2yXH=I2g{+c8 z5vD0~C<5J=M_B?&&Nwz*#^`hz$EC{{lP+UyN=8YI#aK#KsUvHTmiQj9Cjn0ao&-Dz zcoOg=;7P!ffF}V@0-gjs33w9lB;ZNFlYl1yPXe9|O{0Z#&+1Uw0N z67VG8Nx+kUCjn0ao&-DzcoOg=;7P!ffF}V@0-gjs33w9lB;ZNFlYl1yPXe9|O{0Z#&+1Uw0N67VG8Nx+kUCjn0ao&-DzcoOg=;7P!ffF}V@0-gjs33w9l zB;ZNFlYl1yPXe9|O{0Z#&+1Uw0N67VG8Nx+kUCjn0ao&-DzcoOg= z;7P!ffF}V@0-gjs33w9lB;ZNFlYl1yPXe9|O{0Z#&+1Uw0N67VG8 zNx+kUCjn0ao&-DzcoOg=;7P!ffF}V@0-gjs33w9lB;ZNFlYl1yPXe9|O{0Z#&+1Uw0N67VG8Nx+kUCjn0ao&-DzcoOg=;7P!ffF}V@0-gjs33w9lB;ZNF zlYl1yPXe9|O{0Z#&+1Uw0N67VG8Nx+kUCjn0ao&-DzcoOg=;7P!f zfF}V@0-gjs33w9lB;ZNFlYl1yPXe9|O{0Z#&+1Uw0N67VG8Nx+kU zCjn0ao&-DzcoOg=;7P!ffF}V@0-gjs33w9lB;ZNFlYl1yPXe9|O{ z0Z#&+1Uw0N67VG8Nx+kUCjn0ao&-DzcoOg=;7P!ffF}V@0-gjs33w9lB;ZNFlYl1y zPXe9|O{0Z#&+1Uw0N67VG8Nx+kUCjn0a|2q=seqfMcY<}4=?t_~K zHyQ3^xTE0)!Tks>2hM=|*Gq=61MYLUzr%e3_W|6yaBsl<5$+|pr{I1GcOTqsaBJYg zaOc9+!JP$H16K$)4(=GZgW>jv>kaqKi-xfs?k{j}!fk8=CT>`fnZV}ws za5Lei!M*hYcz}Bz?s2$>;qHdJ3GNEGHE^fG?F;wX7Q<+TTM4%eZa&-@a8uw;gc}UE zKU^l<7n=>^L%7%Bo`HK5?iX;E!kq_K4_5;>4(@2U4bL0KgK&4iT?w}ut{HAGIP*Ef z_z3RLaGT(M2lpu418{f2T?y9#w*syn?lidjpEZm-;nu=k3U@KwGPntF#c<={j(|H1 z?niKa;U0g+Fn$epE8O*PSHXqgE`S>XHvp~=TozpHY19$!?{Ig+-2vAIcQM?Ba7}O( zaHqhX05=M5DBONduW zYT-_Yn*mn^cO2Y7aQnmMz40Cxaf9-I$u*At)*_YvINaIe5U1-Ak2LAbl&*1_EZcLiK4+<9<| z;pW1f{(nlY@92>4b^+kAXIwJ`wPNoPE4HW|vsQuI(lM0TDZHxCcE%a@$v z7zf!-GAo$JWQOr3k+h=~O{q$Gij#{hJUiy@@jV$_;Vj45&t}%Jgt^2qia~UzGi_-_ zQyNf_vXmeTFF$gJxJEj&=t_MGa{FjNz%G_Dl5iSPiIP0~Fd*P3?s9>TSxOvZ=tE~3 zQk}eH;@**ffK%*d8LX@1@3y!oE5xy2>YIl=+9u#CA(Wg@Xe5kWXjsZC|d zQiR;R+^e7QJNLQGb*^xR18idn@ywzxoe855Ie5Ou{Pdy&#rbEqy24F9;~-m!r5QQN z#FJglf$zA%MLuK?>siWM44@O`DMlWC+38%^&3Zy9Og0|vFc!ynkI@VyoKS+v&DHJp z$aqE(Lp1&ALTkdPM>!zVrZJ3x^ySJHe@iU2s6sgc$w6iwZ?;}O;|vGb&L$Fhhq1)clL*=q zMtSm+i^rSPd>)X&QFgJON%W!-l?md{_ni@GY-0^`7|RHT(1rGd(}+5hB!~k1v(b6; zH5WL>DkjpO&V&)flN9UXA}82E60?Y7C{gsL6K$wPMamM$^9|y`WzspyA(C0mBIYxb z2@ItZuhX0=lqZ<{WaW9XF}c8Ljx&uew52|^DM@~^^7nf0S-#{vAFz={#M6ON1o3K} zIe5S~WN?O)e8fIBv66Yj(wQ2B5X9BB>NTlsA&Ge2pgnp;=x%CvYz>jBZ}6P zp#(X}#FNGL&Rs5%PAVy^Wj>P_%P=D8N=I7IfNE5vIN5l<$hbV@J8p7`v!s(s3UirE zB;i!2Ac17!ulE81{)eCVnlHJ)Vb-&Z`NR=TOX^dN(&XmXg=#+;Tqd0l*+L3QEMPjr zh@=~Bs83CblaFjXT;SV*n|#hGc9B972~1`zZxBvXDicC5`N+b*6O6?jzTh0ENMj9) zNnk32=}mV!5=s?9C`k@7^PhM*$G`c846gApN7=_Fl3B(qh7n0OIucGzs!)oeWagjw z_D=?vImt2hvyn9{;w^g9osP7m9>oYG3;)bhL->xnT;ns2aEKHZF_SnZ5JO+O(~*|c zp$f&xMJE27s}695vz+88TSy_1dCX)2L+Lzkb?jo&5}2K!6zJK4_jHvLT2zT z(F~v~;WVQm)hJ0Gvhi}J+RP8!<_pepoc*k00dttja0b(xPPCvtl_|`#836&maf8oD zWe4k6LISfG$#A0RMjOJYK`?>5nyz2-3mIJGC_C9gGV#o25@U&^7wu?7O)684Aad~6 zG(DYf$lweo`G9?FXC3b`l`+IHh)%Sn38B=WECtEJ)2Z@>pSjKz&hRlu*v)#D5YJ3T zFpNlg(wUajp&a?i#p5Z)<_9vkOgaU~!izXHlkd63RnCycCf1S2bS5)`H|Rh!YEp=t zyqK(pa+6Ql#U@rVpK%P~*LT$~wodYPqye=kOdxmOQQJ7iQU+0pykz6jL~CL(GZ@b> z`q7<^G^Y+#DMbOY@y7&b!9A{VmZR)p1Iw7tI7TvzwzQ-yC3rDj%(%{fbCENobBL|1 zVgb__&qxN+o36AbjCxe0BtaA)JCEKL7jAKx)m$9s{<4R0L=i$R?u<1r3yC6xT-+Js z_beoe5OQ&6wBNIkD6WpO2ad9rL}KW|>y#xgk4E}mu5yu2*vw+)5XV4Xr!JK##NQ+2 z7`Hh^8rw)mz}v*ogZ8wbEJex3ufx1iILl6E zF`7t1DM^0vkexq=sy$ri6lrW`D&y%#1dXXgDYEfwh(5wthR}yjw4fd#Jc$+)zThZ( zS;GvvQ;Y8hJ8K5ggSLcGlX3)+o0o&El?UA9Fv}Q8H!6~eKi>3SWG=DvpaTu5MhWte ziN6OrE6$S2PEuG&9D@j_2F1z2qXG8Kx7^_ZC)mX*7BYzu^dgM%6sG`B``a@&_?*-1 zWixA;!5Dhcfc*RsB|aP^k!i%znd;={k4Sk*8f%$Mf0|N;0DkDFzOjS#tYSIS7{>rQ z(wu7i*4O%2%Mb?8lL%g?C1KR18YL-0KC<(7AH9-$T;(K-i6@%ww4phbD9As(^+WD) zpr@FS$YK(RV?3jYp)2jFM@`C5fCoLqh@)&`8Pj=}LDZrO0sPWk|KdES*v%s1nawob zWgJoTq8qI#OD;0=Yd3wCuQ*LQAMpVP*hwObNg$5Cw4^cRDNO+~^RTO2<6CZWmE#=Y zAiG$>BI23MTMVE#t!PREYEg`W1oEnjJme1NImHR~lf*ox6H7D$=t@JX5<*FGkck%& z@`cNs;}Cn;&KjmOh8TL#nRYa$EQJXqJC8bhr}BUdPLRg?tYandj3SyS+R~CH)Sw7C z$;9(c&XI5Uip!+2pVcg95z~2#Xd-AwYnoD@QWT>Qf#l?WJ9-E4Gv9HU^L)w)(nw(q zi7Y08DNG=o#?+-a`N&09UUu*u#kYLL4K8q;!)#?E3z)@3Mi5O8+R};|Y-w+9<}i^F z45bxKs6q(AJZz_KbB)hA#R>MZfz>Q!A+wo4ECUIr5mhKkZUT7JRzKrwZgGi|q_UkP z5}3kh2GN@iG^H+OC`2y)^SX8N4YxSSN9<<>Qy4-74Jbtc^6HLXR`5q;mLu_R=3z^1PqUl9@noyIn6eb7H>*_gt%XQ9k zjD5UMBJ-KdNCwiKHZ-IvuaTcDJgp-yxXV>ebA(+avy|CPB!);LXh}UP5=>rR)%ITF zM~;)m0ameu1DUgKp2y@VsIWfWbhOLo30?<|=^Z>o}&-$LAhvi40O^6{#Sd&E61 zag@!hCzO(0FRi|l#4JklV=1}G9;);5HSy#=*Ez{CXczp4X$#IPe^4i+gZy3 zW-*>o45th2X-y+)Q;w1Z@v^A5Er0SOpOV5FRxpBS`cs{Xl;K{GyFeNTNMI&$bRe8& zJS(DxagPkXB$*^;F@=eQ@vM*<%BT6nfcE5Kcc3~#C-QP2ud~f#&&**keQ8ZCf_acz UPO^zfbfP|wbIGHu0ssH=f0e8yP5=M^ literal 0 HcmV?d00001 diff --git a/msamples/dasmm/dasmdbg.c b/msamples/dasmm/dasmdbg.c new file mode 100644 index 0000000..f3e5fe3 --- /dev/null +++ b/msamples/dasmm/dasmdbg.c @@ -0,0 +1,83 @@ +/* Used only for debugging the operand evaluator + This prints the OpType, OpMtype (hex byte), and + if it is a memory operand, it also prints the Base, + Indx, Disp, and size if they exist. + THIS IS NOT INCLUDED IN DELIVERED DASM.EXE +*/ + +void print_Oper(int op) +{ +switch (rgOpType[op]) { + case r32: + fputs("r32= ", lst_fp); + put_num(rgOpReg[op], lst_fp); + break; + case r16: + fputs("r16= ", lst_fp); + put_num(rgOpReg[op], lst_fp); + break; + case r8: + fputs("r8= ", lst_fp); + put_num(rgOpReg[op], lst_fp); + break; + case rCRG: + fputs("rCRG= ", lst_fp); + put_num(rgOpReg[op], lst_fp); + break; + case rDRG: + fputs("rDRG= ", lst_fp); + put_num(rgOpReg[op], lst_fp); + break; + case rTRG: + fputs("rTRG= ", lst_fp); + put_num(rgOpReg[op], lst_fp); + break; + case rSEG: + fputs("rSEG= ", lst_fp); + put_num(rgOpReg[op], lst_fp); + break; + + case mem: /* memory operand */ + fputs("MemOp- ", lst_fp); + if (OpMType & fBase) { /* Base register */ + fputs(" Base-", lst_fp); + put_num(rgOpBase[op], lst_fp); + } + if (OpMType & fIndx) { /* Index Register */ + fputs(" Indx-", lst_fp); + put_num(rgOpIndx[op], lst_fp); + if (OpMType & fScale2) { /* scale value 2 */ + fputs(" Scale2 ", lst_fp); + } + if (OpMType & fScale4) { /* scale value 4 */ + fputs(" Scale4 ", lst_fp); + } + if (OpMType & fScale8) { /* scale value 8 */ + fputs(" Scale8 ", lst_fp); + } + } + if (OpMType & fDisp8) { /* Disp 8 value */ + fputs(" Disp8-", lst_fp); + put_hex(rgOpDisp[op], 2, lst_fp); + } + if (OpMType & fDisp32) { /* Disp 32 value */ + fputs(" Disp32-", lst_fp); + put_hex(rgOpDisp[op], 8, lst_fp); + } + break; + case val8: + fputs("Val8=", lst_fp); + put_num(rgOpDisp[op], lst_fp); + break; + case val16: + fputs("Val16=", lst_fp); + put_num(rgOpDisp[op], lst_fp); + break; + case val32: + fputs("Val32=", lst_fp); + put_num(rgOpDisp[op], lst_fp); + break; + default: + fputs(" UNK Operand ", lst_fp); +} +} diff --git a/msamples/dasmm/dasmq.c b/msamples/dasmm/dasmq.c new file mode 100644 index 0000000..c6e0a19 --- /dev/null +++ b/msamples/dasmm/dasmq.c @@ -0,0 +1,1574 @@ +/* DASMQ.c contains procedures that are stable and are not + subject to change during debugging and development. They + have been moved out of the main module to reduce SCROLL Mania... + +*/ + +/****************************************** +* Determine if a character is alphabetic +* or underscore. These can be used for first +* or subsequent chars in an identifier. +*******************************************/ + +char is_ident(char chr) +{ + return (isalpha(chr)) || (chr == '_'); +} + + +/******************************************** + Determine if character is "skip" character. + All values from 0x20 down to CTRL-A are + skipped. +*********************************************/ + +char isskip(char chr) +{ + if ((chr > 0) && (chr <= ' ')) return(1); + else return(0); +} +/************************************** + Write a Hex byte to a file fout. +***************************************/ + +void put_hexb(U8 value, FILE *fout) +{ +S8 stack[10]; +U32 i, j; + + i = 0; j = 2; + do { + stack[i] = (value % 16) + '0'; + if (stack[i] > 0x39) + stack[i] += 7; + i++; + } + while(value /= 16); + while (i < j--) { /* zero pad front end to width */ + fputc('0', fout); + } + while(i) { + fputc(stack[--i], fout); + } +} + +/************************************** + Write a Hex number to a file fout. +***************************************/ + +void put_hexw(U32 value, FILE *fout) +{ +S8 stack[10]; +U32 i, j; + + i = 0; + j = 4; + do { + stack[i] = (value % 16) + '0'; + if (stack[i] > 0x39) + stack[i] += 7; + i++; + } + while(value /= 16); + while (i < j--) { /* zero pad front end to width */ + fputc('0', fout); + } + while(i) { + fputc(stack[--i], fout); + } +} + +/************************************** + Write a hex dword to a file fout. +***************************************/ + +void put_hexd(U32 value, FILE *fout) +{ +S8 stack[10]; +U32 i, j; + + i = 0; + j = 8; + do { + stack[i] = (value % 16) + '0'; + if (stack[i] > 0x39) + stack[i] += 7; + i++; + } + while(value /= 16); + while (i < j--) { /* zero pad front end to width */ + fputc('0', fout); + } + while(i) { + fputc(stack[--i], fout); + } +} + + +/************************************* + Acquires VALUE for Expression() +*************************************/ +long expr4(long *val) +{ +long k; + +if (Token == rOFFSET) { + fOffset = 1; + Parse(); + } + +if (Token == OPENRND) { /* Open paren */ + Parse(); + k=expr1(val); + if (Token == CLOSRND) { + Parse(); + } + else{ + line_error(1); + return(0); + } + } +else if (Token == NUMBER) { + *val = TNumber; + Parse(); /* set up for next token check */ + } +else if (Token == LSYMBOL) { + nExpSyms++; + *val = lst[TSymnum].Offs; + iExpSym = TSymnum; /* so we can trace symbol number came from */ + ExpType = 1; + Parse(); /* set up for next token check */ + } +else if (Token == SYMBOL) { + nExpSyms++; + *val = gst[TSymnum].Offs; + iExpSym = TSymnum; /* so we can trace symbol number came from */ + ExpType = 2; + Parse(); /* set up for next token check */ + } +else if (Token == UNKSYM) { + nExpSyms++; + *val = 0; /* No offset for UNKSYM */ + iExpSym =0; + ExpType = 0; /* 0 means forward ref. No Assumption. */ + + /* Save name for forward reference */ + strncpy(UString, TString, 30); + if (CBString > 30) + UCBString = 30; + else + UCBString = CBString; /* Size of Unknown label */ + UString[UCBString] = '\0'; /* Null terminate */ + + Parse(); /* set up for next token check */ + } +else if (Token == DOLLAR) { + if (fDataSeg) + *val = oNextData; + else + *val = oNextCode; + ExpType = 3; + Parse(); /* set up for next token check */ + } +else{ + line_error(2); + return(0); + } +return(1); +} + +/***************************************** + Evaluates a UNARY MINUS for Expression() +*****************************************/ +long expr3(long *val) +{ +long k; + +if (Token == MINUS) { /* Unary MINUS */ + Parse(); /* set up for next token check */ + k=expr4(val); + if (k) { + *val = -(*val); + return(1); + } + else { + line_error(3); + return(0); + } + } +else { + k = expr4(val); + return(k); + } +} + + +/************************************* + Evaluates a * and / Expression() +*************************************/ +long expr2(long *val) +{ +long k; +long val2; + +k=expr3(val); +if ((Token != STAR) && (Token != SLASH)) + return(k); +while(1) { + if (Token == STAR) { /* MULTIPLY */ + Parse(); /* set up for next token check */ + if(expr2(&val2)) + *val *= val2; + } + else if (Token == SLASH) { /* DIVIDE */ + Parse(); /* set up for next token check */ + if(expr2(&val2)) + *val /= val2; + } + else return(1); /* Expr doesn't continue but it's OK to here */ +} +} + +/************************************* + Evaluates a + and - for Expression() +*************************************/ +long expr1(long *val) +{ +long k; +long val2; + +k=expr2(val); +if ((Token != PLUS) && (Token != MINUS)) return(k); +while(1) { + if (Token == PLUS) { + Parse(); + if (Token==REGIST) return(1); /* allow for N+REG */ + if(expr2(&val2)) + *val += val2; + else return(0); + } + else if (Token == MINUS) { + Parse(); + if (Token==REGIST) return(1); /* allow for N+REG */ + if(expr2(&val2)) + *val -= val2; + else return(0); + } + else return(1); /* Expr doesn't continue but it's OK to here */ +} +} + +/******************************************* + Expression is called to evaluate a math + expression made of constants, and/or + address labels (offsets). + Uses functions expr1 - expr4 recursively + to handle parenthetical expressions + while keeping standard math operator + precedence correct. Exits with (0) if error + in expression is encountered. Exits with + 1 if value is left in TNumber. If a NON + math Token is encountered but expression + was OK to that point, it calls ReturnToken + and leaves the currenly evaluated number + as the current token. + + If a single symbol or a single "current address" + opeator ($) is used in the expression, it will + return with SYMOFF as the Token type with the + offset value in TNumber, and the symbol + in TSymnum. If the OFFSET operator is used, + it will return with the offset in TNumber + and it will be a NUMOFF. + If more than 1 symbol or the + current address operator ($) and a symbol + is used it will assume a simple numeric + value from the computation and return + NUMBER as it's token. +********************************************/ + +long Expression(void) +{ +long val; + +/* iExpSym = 0; */ +nExpSyms = 0; +fOffset = 0; + +if (expr1(&val)) { + + if (Token) /* if not EOL (EOL returns 0) */ + ReturnToken(); /* give back non-expression token */ + if (nExpSyms == 1) { + if (fOffset) + Token = NUMOFF; /* Derived from OFFSET cmd */ + else + Token = SYMOFF; /* single address operator used (Mem Type) */ + } + else + Token = NUMBER; /* Make current token a NUMBER */ + + TSymnum = iExpSym; /* We can tell where number came from */ + TNumber = val; /* Tell em what it is */ + return(1); /* Tell em they got one */ +} +else return(0); /* Tell em they got an error */ +} + +/***************************************************** + Determines if token is 32 bit general register. +*****************************************************/ +long is_r32(long id) +{ +switch (id) { + case rEAX: + case rEBX: + case rECX: + case rEDX: + case rESI: + case rEDI: + case rEBP: + case rESP: return(1); + default: return(0); + } +} + +/***************************************************** + Determines if token is 16 bit general. +*****************************************************/ +long is_r16(long id) +{ +switch (id) { + case rAX: + case rBX: + case rCX: + case rDX: + case rSI: + case rDI: + case rBP: + case rSP: return(1); + default: return(0); + } +} + +/***************************************************** + Determines if token is 8 bit general register. +*****************************************************/ +long is_r8(long id) +{ +switch (id) { + case rAL: + case rBL: + case rCL: + case rDL: + case rAH: + case rBH: + case rCH: + case rDH: return(1); + default: return(0); + } +} + +/***************************************************** + Determines if token is Segment Register. +*****************************************************/ +long is_rSEG(long id) +{ +switch (id) { + case rDS: + case rES: + case rCS: + case rFS: + case rGS: + case rSS: return(1); + default: return(0); + } +} + +/***************************************************** + Determines if token is Debug register. +*****************************************************/ +long is_rDRG(long id) +{ +switch (id) { + case rDR0: + case rDR1: + case rDR2: + case rDR3: + case rDR6: + case rDR7: return(1); + default: return(0); + } +} + +/***************************************************** + Determines if token is Control register. +*****************************************************/ +long is_rCRG(long id) +{ +return ((id == rCR0) || (id == rCR2) || (id == rCR3)); +} + +/***************************************************** + Determines if token is Test register. +*****************************************************/ +long is_rTRG(long id) +{ +return ((id == rTR6) || (id == rTR7)); +} + +/***************************************************** + Determines if operand entry in instruction (ins) is + compatible with the operand type the user gave (op). + An entry of 0 may match which means there is no + operand. +*****************************************************/ + + +long is_Comp(long ins, long op) +{ +switch (rgINS[ins][op+1]) { /* check against op type in instruction */ + case 0: + if (!rgOpType[op]) return(1); /* no operand in either matches */ + break; + case rel8: + if (rgOpType[op] == rel8) return(1); + break; + case relW: + if (rgOpType[op] == relW) return(1); + break; + case iSAD: + if (rgOpType[op] == r8) return(1); + break; + case r8: + if (rgOpType[op] == r8) return(1); + break; + case r16: + if (rgOpType[op] == r16) return(1); + break; + case r32: + if (rgOpType[op] == r32) return(1); + break; + case rREG: + if ((rgOpType[op] == r8) || + (rgOpType[op] == r16) || + (rgOpType[op] == r32)) return(1); + break; + case rRGW: + if ((rgOpType[op] == r16) || + (rgOpType[op] == r32)) return(1); + break; + case rACC: + if (((rgOpType[op] == r8) && (rgOpReg[op] == rAL)) || + ((rgOpType[op] == r16) && (rgOpReg[op] == rAX)) || + ((rgOpType[op] == r32) && (rgOpReg[op] == rEAX))) + return(1); + break; + case rSEG: + if (rgOpType[op] == rSEG) return(1); + break; + case rCRG: + if (rgOpType[op] == rCRG) return(1); + break; + case rDRG: + if (rgOpType[op] == rDRG) return(1); + break; + case rTRG: + if (rgOpType[op] == rTRG) return(1); + break; + case imm8: + if (rgOpType[op] == val8) + return(1); + + if ((rgOpType[op] == val16) && + (OpImm < 256) && + (OpImm >= 0)) + return(1); + + break; + case ims8: /* This is where a byte in an instruction + will be sign extended. We will only allow byte values + between -128 and 127 to be compatible here. This is because + they can put AND EAX, A0h and we have to assume they DON'T + want it extended into a negative 32 bit integer such as 0FFFFFFA0h. + */ + if (rgOpType[op] == val8) + return(1); + + if ((rgOpType[op] == val16) && + (OpImm < 128) && + (OpImm >= 0)) + return(1); + + break; + case imm16: + if ((rgOpType[op] == val8) || + (rgOpType[op] == val16)) return(1); + break; + case immX: + if ((rgOpType[op] == val8) || + (rgOpType[op] == val16) || + (rgOpType[op] == val32)) return(1); + break; + case rm8: + if ((rgOpType[op] == r8) || + ((rgOpType[op] == mem) && (OpSize[op] & fByte))) return(1); + break; + case rm16: + if ((rgOpType[op] == r16) || + ((rgOpType[op] == mem) && (OpSize[op] & fWord)) ) return(1); + break; + case rRM: + if ((rgOpType[op] == r8) || + (rgOpType[op] == r16) || + (rgOpType[op] == r32) || + (rgOpType[op] == mem)) return(1); + break; + case rRMW: + if (rgOpType[op] == mem) + { + if (OpSize[op] & fFWord) + return(0); + if (OpSize[op] & fByte) + return(0); + return(1); + } + if ((rgOpType[op] == r16) || + (rgOpType[op] == r32)) + return(1); + break; + case mem: + if ((rgOpType[op] == mem) && (!(OpSize[op] & fFWord))) return(1); + break; + case memF: + if ((rgOpType[op] == memF) && (OpSize[op] & fFWord)) return(1); + break; + case moff: + if ((rgOpType[op] == mem) && + (OpMType & fDisp32) && + ((OpMType & fIndx)==0) && + ((OpMType & fBase)==0)) + return(1); + break; + case immv3: + if ((rgOpType[op] == val8) && + (OpImm == 3)) return(1); + break; + case immv1: + if ((rgOpType[op] == val8) && + (OpImm == 1)) return(1); + break; + case rDX: + if ((rgOpType[op] == r16) && + (rgOpReg[op] == rDX)) return(1); + break; + case rCL: + if ((rgOpType[op] == r8) && + (rgOpReg[op] == rCL)) return(1); + break; + case rAL: + if ((rgOpType[op] == r8) && + (rgOpReg[op] == rAL)) return(1); + break; + case rAX: + if ((rgOpType[op] == r16) && + (rgOpReg[op] == rAX)) return(1); + break; + case rEAX: + if ((rgOpType[op] == r32) && + (rgOpReg[op] == rEAX)) return(1); + break; + case rCS: + case rSS: + case rDS: + case rES: + case rFS: + case rGS: + if ((rgOpType[op] == rSEG) && + (rgOpReg[op] == rgINS[ins][op+1])) return(1); + break; + default:; + } +return(0); +} + +/***************************************************** + Determines if entry in rgOpType is a register. +*****************************************************/ + +long is_Reg(long op) +{ + switch (op) { /* This should be the value from rgOpType[x] */ + case r8: + case r16: + case r32: + case rCRG: + case rDRG: + case rTRG: + return(1); + default:; + } + return(0); +} + + +/********************************************* +This displays the string and exits for a FATAL +assembler error. +**********************************************/ + +void fatal_error(S8 *pst) +{ + +++error_count; + +if (fListA | fListE) { + fprintf(lst_fh, "\r\nFATAL ERROR, line %ld - %s\r\n", lineno[level], pst); + +/* + DumpGSymbols(); + DumpLSymbols(); +*/ + fclose(lst_fh); + } + +printf("\r\nFATAL ERROR, line %ld - %s\r\n", lineno[level], pst); +printf("%d Errors\r\n%d Warnings\r\n", error_count, warn_count); + +exit(1); +} + +/********************************************* +This displays the string and line number for +non-fatal errors. +**********************************************/ + +void line_error(long num) +{ +S8 *p; + + switch (num) { + case 1: p="Invalid expression, ')' expected"; break; + case 2: p="Invalid expression, value expected"; break; + case 3: p="Value expected after unary '-'"; break; + case 4: p="Too many digits for numeric radix"; break; + case 5: p="Invalid character in a number"; break; + case 6: p="Unterminated string"; break; + case 7: p="Unrecognized character"; break; + case 8: p="Invalid Alignment specified"; break; + case 9: p="Start command only allowed in CSEG"; break; + case 10: p="Virtual command must be first in segment"; break; + case 11: p="Invalid Virtual value"; break; + case 12: p="Starting address not found"; break; + case 13: p="Stack command not allowed in DSEG"; break; + case 14: p="Invalid DOT command"; break; + case 15: p="Invalid Operand"; break; + case 16: p="Invalid segment register use"; break; + case 17: p="Invalid scale value 'Reg*?'"; break; + case 18: p="Scale value expected (*2,*4,*8)"; break; + case 19: p="Too many address scale values"; break; + case 20: p="Invalid register for memory operand"; break; + case 21: p="Invalid memory operand"; break; + case 22: p="Offset must be from data segment"; break; + case 23: p="Nested brackets"; break; + case 24: p="Unbalanced brackets"; break; + case 25: p="Invalid operand size attribute"; break; + case 26: + case 27: + case 28: + case 29: + case 30: + case 31: p=""; break; + case 32: p="Unknown token in operand array"; break; + case 33: p="Too many operands or extra character"; break; + case 34: p=""; break; + case 35: p="Invalid expression or numeric value"; break; + case 36: p="Operand expected before comma"; break; + case 37: p=""; break; + case 38: p="Invalid character or reserved word in operand"; break; + case 39: p="Relative jump out of range"; break; + case 40: p="Operand size NOT specified or implied"; break; + case 41: p="Instructions not allowed in data segment"; break; + case 42: p="Instruction expected after prefix"; break; + case 43: p="Operand sizes don't match"; break; + case 44: p="Wrong operand type for instruction"; break; + case 45: p="Incorrect format for memory operand"; break; + case 46: p="Strings only valid for DB storage"; break; + case 47: p="Expected '(' after 'DUP'"; break; + case 48: p="Storage expected between commas"; break; + case 49: p="':' not expected"; break; + case 50: p="DWord storage required for OFFSET"; break; + case 51: p="Invalid storage value"; break; + case 52: + case 53: p=""; break; + case 54: p="':' expected after last label"; break; + case 55: p="Macro not allowed in lexical level 0"; break; + case 56: p="EQU or Storage expected"; break; + case 57: + case 58: + case 59: + case 60: + case 61: + case 62: p=""; break; + case 63: p="Instruction expected before register name"; break; + case 64: p="Public Symbol already defined"; break; + case 65: p="Local symbol already defined"; break; + case 66: p="Number not expected"; break; + case 67: p="New symbol must follow PUBLIC keyword"; break; + case 68: p="Label, Command, Instruction, or Storage expected"; break; + case 69: p="Inconsistant redeclaration"; break; + case 70: p=""; break; + default: + break; + } + + fprintf(lst_fh, "\r\nERROR: %d, line: %ld, %s\r\n", num, lineno[level], p); + *line_ptr = 0; /* this KILLS the rest of the line */ + Column = 0; + ++error_count; +} + +/********************************************* +This displays the string and line number for +errors dicovered AFTER we past the line. +This is for non-fatal errors. +**********************************************/ + +void prev_error(S8 *pst, S32 line) +{ + fprintf(lst_fh, "\r\nERROR, line %d - %s\r\n", line, pst); + Column = 0; + ++error_count; +} + +/********************************************************** + The parser calls this when it detects a digit leaving + the line_ptr* pointing to digit. It accepts base 2, 10 + & 16. Base 2 numbers are suffixed with a B or b, base 16 + with an h or H and base 10 with no suffix. +***********************************************************/ + +U32 get_number(void) +{ +U32 value, base; +S8 c, i; +S32 len; +S8 st[33]; + value = 0; + len = 0; + base = 10; /* default base is 10 */ + + while(isxdigit(c = *line_ptr)) { /* get all the digits */ + st[len++] = c; + line_ptr++; + } + + if ((*line_ptr== 'h') || (*line_ptr== 'H')) { /* looks like hex */ + line_ptr++; + base = 16; + } + else if ((st[len-1] == 'b') || (st[len-1] == 'B')) { + base = 2; + len--; + } + if (((base == 2) && (len > 33)) || + ((base == 10) && (len > 10)) || + ((base == 16) && (len > 9))) { + line_error(4); + return(0); + } + i = 0; + do { + c = st[i]; + if(isdigit(c)) /* convert numeric digits */ + c -= '0'; + else if(c >= 'a') /* convert lower case alphas */ + c -= ('a' - 10); + else if(c >= 'A') /* convert upper case alphas */ + c -= ('A' - 10); + else + break; + if(c >= base) { /* outside of base */ + line_error(5); + return(0); + } + value = (value * base) + c; /* include in total */ + i++; } + while(i < len); /* to length of string */ + return value; +} + +/********************************************* +This is a fast binary search for a reserved +word that is not an instructions or a register. +**********************************************/ + +S32 findrsvd(S8 *pb, S32 cb) /* pointer to and size of string */ +{ +S32 f, m, n, k; +S8 id[8]; + + if (cb>srsvd) return(0); /* can't be a reserved word */ + strncpy(id, pb, cb); /* move string local */ + id[cb] = 0; /* null terminate */ + + m = 0; + n = nreserved-1; + while (m<=n) { + k = m + (n-m) / 2; + f = strncmp(id, rgReserved[k], srsvd-1); + if (!f) return(k + nrsvd1); /* found it! */ + else if (f > 0) /* it was less */ + m = k+1; + else /* it was more */ + n = k-1; + } + return(0); +} + +/********************************************* +This is a fast binary search for an instuction. +It returns the number or 0 if not found. +**********************************************/ + +S32 findinst(S8 *pb, S32 cb) /* pointer to and size of parsed string */ +{ +S32 f, m, n, k; +S8 id[6]; + + if (cb>sinst) return(0); /* can't be an instruction */ + strncpy(id, pb, cb); /* move string local */ + id[cb] = 0; /* null terminate */ + + m = 0; + n = ninst-1; + while (m<=n) { + k = m + (n-m) / 2; + f = strncmp(id, rginst[k], sinst-1); + if (!f) return(k+1); /* found it! */ + else if (f > 0) /* id was less */ + m = k+1; + else /* idwas more */ + n = k-1; + } + return(0); +} + +/********************************************* +This is a fast binary search for a register. +It returns the number or 0 if not found. +**********************************************/ + +S32 findreg(S8 *pb, S32 cb) /* pointer to, and size of parsed string */ +{ +S32 f, m, n, k; +S8 id[3]; + + if ((cb>sregs-1) || (cb<2)) return(0); /* can't be a register */ + strncpy(id, pb, cb); /* move string local */ + id[cb] = 0; /* null pad */ + + m = 0; + n = nregs-1; + while (m<=n) { + k = m + (n-m) / 2; + f = strncmp(id, rgreg[k], sregs-1); + if (!f) return(k+nreg1); /* found it! */ + else if (f > 0) /* it was less */ + m = k+1; + else /* it was more */ + n = k-1; + } + return(0); +} + +/********************************************* +This searches the LOCAL symbol table for the name +described by pb, cb. It only compares items that +are the same length (cb == TSymsize[x]). +It returns the number or 0 if not found. +**********************************************/ + +S32 findLsymbol(S8 *pb, S32 cb) /* pointer to, and size of string */ +{ +S32 i; +S8 name[132]; + +strncpy(name, pb, cb); /* move name local */ +name[cb] = 0; /* null terminate */ + +i = iLSymNext; +while (i>1) { /* backwards through symbol table */ + i--; + /* Only compare if same size */ + if (lst[i].Size == cb) { + if (strncmp(name, lst[i].Ptr, cb) == 0) return(i); + } + } +return(0); /* not found... */ +} + + +/********************************************* +This searches the symbol table for the name +described by pb, cb. It only compares items that +are the same length (cb == TSymsize[x]). +If the include level is greater than 0 it +searches the local first, then the global. +If at level 0, it only searches the global. +It returns the number or 0 if not found. +**********************************************/ + +S32 findGsymbol(S8 *pb, S32 cb) /* pointer to, and size of string */ +{ +S32 i; +S8 name[132]; + +strncpy(name, pb, cb); /* move name local */ +name[cb] = 0; /* null terminate */ + +i = iSymNext; +while (i>1) { /* backwards through symbol table */ + i--; + /* Only compare if same size */ + if (gst[i].Size == cb) { + if (strncmp(name, gst[i].Ptr, cb) == 0) return(i); + } + } +return(0); /* not found... */ +} + +/********************************************* + DUMP SYMBOL TABLE FOR TESTING +**********************************************/ + +void DumpGSymbols(void) +{ +S32 i; +S8 name[132]; + +fprintf(lst_fh, "PUBLIC SYMBOLS: \r\n"); + +i = 1; +while (i 0) + line_error(10); + else { + if (fListA) + Column += fprintf(lst_fh, "%08lX", TNumber); + oNextData = TNumber; + DataOffset = TNumber; + } + } + else + line_error(11); + } + else { + if (fListA) + Column += fprintf(lst_fh, "VIRTUAL Segment address: "); + if (Parse() == NUMBER) { + if (oNextCode > 0) + line_error(10); + else { + if (fListA) + Column += fprintf(lst_fh, "%08lX", TNumber); + oNextCode = TNumber; + CodeOffset = TNumber; + } + } + else + line_error(11); + } + break; + case rINCLUDE: + tmpname[0] = 0; /* default to null name */ + while (isskip(*line_ptr)) line_ptr++; + i=0; + while ((*line_ptr) && (*line_ptr != ';') && (!isskip(*line_ptr))) + tmpname[i++] = *line_ptr++; + tmpname[i] = 0; /* null terminate */ + + DoInclude(tmpname); + break; + case rSEARCH: + tmpname[0] = 0; /* default to null name */ + while (isskip(*line_ptr)) line_ptr++; + i=0; + while ((*line_ptr) && (*line_ptr != ';') && (!isskip(*line_ptr))) + tmpname[i++] = *line_ptr++; + tmpname[i] = 0; /* null terminate */ + + DoSearch(tmpname); + break; + case rSTACK: + if (!fDataSeg) { + if (fListA) + Column += fprintf(lst_fh, "Stack Total: "); + if (Parse() == NUMBER) { + StackTotal += TNumber; + if (fListA) + Column += fprintf(lst_fh, "%08lX", StackTotal); + } + else + line_error(35); /* Invalid number or expression */ + } + else + line_error(13); + break; + default: line_error(14); + return; +} +} + +/******************************************** + This adds the 3 bit code for the specified + register to the ModRM or SIB bytes which + is pointed to by *modbyte. nshift is the + number of bits to shift the register code + before ORing it with *modbyte (ModRM or SIB). +*********************************************/ + +void EncodeRegBits(S32 regnum, S8 *modbyte, S32 nshift) +{ + +switch (regnum) { + case rAL: + case rAX: /* value is 1 don't do anything */ + case rEAX: + case rES: + case rCR0: + case rDR0: + break; + case rCL: + case rCX: + case rECX: + case rCS: + case rCR1: + case rDR1: + *modbyte |= (1 << nshift); + break; + case rDL: + case rDX: + case rEDX: + case rSS: + case rCR2: + case rDR2: + *modbyte |= (2 << nshift); + break; + case rBL: + case rBX: + case rEBX: + case rDS: + case rCR3: + case rDR3: + *modbyte |= (3 << nshift); + break; + case rAH: + case rSP: + case rESP: + *modbyte |= (4 << nshift); + break; + case rCH: + case rBP: + case rEBP: + case rFS: + *modbyte |= (5 << nshift); + break; + case rDH: + case rSI: + case rESI: + case rGS: + case rTR6: + case rDR6: + *modbyte |= (6 << nshift); + break; + case rBH: + case rDI: + case rEDI: + case rTR7: + case rDR7: + *modbyte |= (7 << nshift); + break; + default:; /* if it's not one of these we do nothing */ +} +} + +/******************************************** + Add Macro to LOCAL symbol table. + The last symbol added to the symbol + table is the label for this macro. + +*********************************************/ +void AddMacro(void) +{ +S32 i, j; +S8 mac[100]; + +mac[0] = 0; + +if (iMacNext >= MACBUFMAX-50) + fatal_error("Macro buffer overflow..."); +if (iMacNext >= MACSMAX) + fatal_error("Macro table overflow..."); + +i = 0; j = 0; +while(isskip(*line_ptr)) line_ptr++; /* skip while space */ + +/* Read the macro including white space upto EOL or comment. + j keeps track of the last NON-space character so we don't + store unneeded spaces at the end of the macro. +*/ + +while ((*line_ptr) && (*line_ptr != SEMI)) { + mac[i++] = *line_ptr++; + if (mac[i-1] > 0x20) j = i; /* j will be length */ +} + +strncpy(pMacNext, mac, j); + +/* These are all "iLSymNext-1" because the Macro label has + already been added to the symbol table when AddMacro + is called. +*/ + +lst[iLSymNext-1].Type = 0; /* cancel previous type */ +lst[iLSymNext-1].Type |= MACRO; /* initialize type */ + +rgMacPtr[iMacNext] = pMacNext; /* store mac ptr in pmac array */ +lst[iLSymNext-1].Offs = iMacNext; /* store mac # in offset */ +iMacNext++; +pMacNext += j; +*pMacNext = 0; /* null terminate the macro */ +pMacNext++; + +} diff --git a/msamples/dasmm/makeit.bat b/msamples/dasmm/makeit.bat new file mode 100644 index 0000000..9a9e5dd --- /dev/null +++ b/msamples/dasmm/makeit.bat @@ -0,0 +1,2 @@ +CM32 DASM.c +DASM DASM.ATF diff --git a/msamples/dasmm/read.me b/msamples/dasmm/read.me new file mode 100644 index 0000000..a843487 --- /dev/null +++ b/msamples/dasmm/read.me @@ -0,0 +1,13 @@ +This is the DASM Assembler ported to run under MMURTL. +It has been modified to use MMURTL memory management +calls directly. +It produces the same run file as its DOS counterpart. +You will notice, the like the ported version of CM32, +it runs slower (about 150%) than the DOS version. + +This is for 2 reasons. The CM32 compiler was used to build it. +CM32 is hardly a "production" compiler. +Its code generation is no competition for the likes of Borland. +The second reason is that the processor is being shared with +several other tasks that wake up and do things (such as +display the time or tick count in the monitor). -- 2.40.0