/*++ Copyright (c) 1993 Digital Equipment Corporation Module Name: assem.c Abstract: This file contains the set of routines which assemble an instruction on Alpha. Author: Miche Baker-Harvey Environment: Win32 - User --*/ /******************** INCLUDE FILES *******************************/ #include "precomp.h" #pragma hdrstop #include #include "optable.h" #include "ntasm.h" #include "ntdis.h" #include "strings.h" #define OPSIZE 16 int assem(PULONG, PUCHAR, PULONG); BOOLEAN TestCharacter (PUCHAR, PUCHAR *, UCHAR ch); ULONG GetIntReg(PUCHAR, PUCHAR *); ULONG GetFltReg(PUCHAR, PUCHAR *); ULONG GetValue(PUCHAR, PUCHAR *, BOOLEAN, ULONG, PULONG, CHAR); PUCHAR SkipWhite(PUCHAR *); ULONG GetToken(PUCHAR, PUCHAR *, PUCHAR, ULONG); /*** assem - assemble instruction * * Purpose: * To assemble the instruction pointed by *poffset. * * Input: * instruction - where to put the assembled instruction * pchInput - pointer to string to assemble * poffset - * * Output: * status - see ntasm.h for codes * * Exceptions: * error exit: xosd * * Notes: * errors are handled by the calling program by outputting * the error string and reprompting the user for the same * instruction. * **************************************************************/ int assem (PULONG instruction, PUCHAR pchInput, PULONG poffset) { UCHAR szOpcode[OPSIZE]; ULONG status; POPTBLENTRY pEntry; // // Using the mnemonic token, find the entry in the assembler's // table for the associated instruction. // if (GetToken(pchInput, &pchInput, szOpcode, OPSIZE) == 0) { return(BADOPCODE); } if ((pEntry = findStringEntry(szOpcode)) == (POPTBLENTRY) -1) { return(BADOPCODE); } if (pEntry->eType == INVALID_ETYPE) { return(BADOPCODE); } // // Use the instruction format specific parser to encode the // instruction plus its operands. // status = (*pEntry->parsFunc) (pchInput, pEntry, poffset, instruction); return (status); } BOOLEAN TestCharacter (PUCHAR inString, PUCHAR *outString, UCHAR ch) { inString = SkipWhite(&inString); if (ch == *inString) { *outString = inString+1; return TRUE; } else { *outString = inString; return FALSE; } } /*** GetIntReg - get integer register number *** GetFltReg - get floating register number * * Purpose: * From reading the input stream, return the register number. * * Input: * inString - pointer to input string * * Output: * *outString - pointer to character after register token in input stream * * Returns: * register number * * Exceptions: * error(BADREG) - bad register name * *************************************************************************/ PUCHAR regNums[] = { "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23", "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31" }; PUCHAR intRegNames[] = { szR0, szR1, szR2, szR3, szR4, szR5, szR6, szR7, szR8, szR9, szR10, szR11, szR12, szR13, szR14, szR15, szR16, szR17, szR18, szR19, szR20, szR21, szR22, szR23, szR24, szR25, szR26, szR27, szR28, szR29, szR30, szR31 }; PUCHAR fltRegNames[] = { "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31" }; ULONG GetIntReg (PUCHAR inString, PUCHAR *outString) { UCHAR szRegOp[5]; ULONG index; if (!GetToken(inString, outString, szRegOp, sizeof(szRegOp))) return(BADREG); if (szRegOp[0] == '$') { // // use numbers // for (index = 0; index < 32; index++) { if (!strcmp(szRegOp, regNums[index])) return index; } } else { // // use names // for (index = 0; index < 32; index++) { if (!strcmp(szRegOp, intRegNames[index])) return index; } } return(BADREG); } ULONG GetFltReg (PUCHAR inString, PUCHAR *outString) { UCHAR szRegOp[5]; ULONG index; if (!GetToken(inString, outString, szRegOp, sizeof(szRegOp))) return(BADREG); if (szRegOp[0] == '$') { // // use numbers // for (index = 0; index < 32; index++) { if (!strcmp(szRegOp, regNums[index])) return index; } } else { // // use names // for (index = 0; index < 32; index++) { if (!strcmp(szRegOp, fltRegNames[index])) return index; } } return(BADREG); } /*** GetValue - get value from command line * * Purpose: * Use GetExpression to evaluate the next expression in the input * stream. * * Input: * inString - pointer to input stream * fSigned - TRUE if signed value * FALSE if unsigned value * bitsize - size of value allowed * * Output: * outString - character after the last character of the expression * outValue - where to return the value * * Returns: * GOODINSTRUCTION, or error from ntasm.h * * Exceptions: * return exit: OVERFLOW - value too large for bitsize * *************************************************************************/ ULONG GetValue (PUCHAR inString, PUCHAR *outString, BOOLEAN fSigned, ULONG bitsize, PULONG valuep, CHAR ch) { ULONG value, index, err; inString = SkipWhite(&inString); // // find the character that marks the end of the string, // and replace it with a null; // otherwise, the expression evaluator fails // for ( index = 0; /**/ ; index++ ) { if (inString[index] == ch) { inString[index] = '\0'; break; } if (inString[index] == '\0') { return OPERAND; } } // // This is a callback to the shell which does the work. // err = DHGetNumber(inString, &value); // // first replace any overwritten character // inString[index] = ch; // // DHGetNumber returns 0 if it succeeds. // if ( err != GOODINSTRUCTION ) { return err; } if ((value > (ULONG)(1L << bitsize) - 1) && (!fSigned || (value < (ULONG)(-1L << (bitsize - 1))))) return OVERFLOW; *outString = inString + index; *valuep = value; return GOODINSTRUCTION; } /*** SkipWhite - skip white-space * * Purpose: * To advance pchCommand over any spaces or tabs. * * Input: * *pchCommand - present command line position * *************************************************************************/ PUCHAR SkipWhite (PUCHAR * string) { while (**string == ' ' || **string == '\t') (*string)++; return(*string); } /*** GetToken - get token from command line * * Purpose: * Build a lower-case mapped token of maximum size maxcnt * at the string pointed by *psz. Token consist of the * set of characters a-z, A-Z, 0-9, $, and underscore. * * Input: * *inString - present command line position * maxcnt - maximum size of token allowed * * Output: * *outToken - token in lower case * *outString - pointer to first character beyond token in input * * Returns: * size of token if under maximum else 0 * * Notes: * if string exceeds maximum size, the extra characters * are still processed, but ignored. * *************************************************************************/ ULONG GetToken (PUCHAR inString, PUCHAR *outString, PUCHAR outToken, ULONG maxcnt) { UCHAR ch; ULONG count = 0; inString = SkipWhite(&inString); while (count < maxcnt) { ch = (UCHAR)tolower(*inString); if (!((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'z') || (ch == '$') || (ch == '_') || (ch == '#'))) break; count++; *outToken++ = ch; inString++; } *outToken = '\0'; *outString = inString; return (count >= maxcnt ? 0 : count); } /*** ParseIntMemory - parse integer memory instruction * * Purpose: * Given the users input, create the instruction. * * Input: * inString - present input position * pEntry - pointer into the opTable for this opcode * poffset - pointer to offset where assembled instr will go * pinstruction - pointer to where to put the instruction * * Output: * &pinstruction - the assembled instruction * * Returns: * the error code, or GOODINSTRUCTINO * * Format: * op Ra, disp(Rb) * *************************************************************************/ ULONG ParseIntMemory(PUCHAR inString, POPTBLENTRY pEntry, PULONG poffset, PULONG instruction) { ULONG Ra; ULONG Rb; ULONG disp; ULONG err; Ra = GetIntReg(inString, &inString); if (!TestCharacter(inString, &inString, ',')) return(OPERAND); err = GetValue(inString, &inString, TRUE, WIDTH_MEM_DISP, &disp, '('); if (err != GOODINSTRUCTION) return err; if (!TestCharacter(inString, &inString, '(')) return(OPERAND); Rb = GetIntReg(inString, &inString); if (!TestCharacter(inString, &inString, ')')) return(OPERAND); if (!TestCharacter(inString, &inString, '\0')) return(EXTRACHARS); *instruction = OPCODE(pEntry->opCode) + REG_A(Ra) + REG_B(Rb) + MEM_DISP(disp); return(GOODINSTRUCTION); } /*** ParseFltMemory - parse floating point memory instruction * * Purpose: * Given the users input, create the memory instruction. * * Format: * op Fa, disp(Rb) * *************************************************************************/ ULONG ParseFltMemory(PUCHAR inString, POPTBLENTRY pEntry, PULONG poffset, PULONG instruction) { ULONG Fa; ULONG Rb; ULONG disp; ULONG err; Fa = GetFltReg(inString, &inString); if (!TestCharacter(inString, &inString, ',')) return(OPERAND); err = GetValue(inString, &inString, TRUE, WIDTH_MEM_DISP, &disp, '('); if (err != GOODINSTRUCTION) return err; if (!TestCharacter(inString, &inString, '(')) return(OPERAND); Rb = GetIntReg(inString, &inString); if (!TestCharacter(inString, &inString, ')')) return(OPERAND); if (!TestCharacter(inString, &inString, '\0')) return(EXTRACHARS); *instruction = OPCODE(pEntry->opCode) + REG_A(Fa) + REG_B(Rb) + MEM_DISP(disp); return(GOODINSTRUCTION); } /*** ParseMemSpec - parse special memory instruction * * Purpose: * Given the users input, create the memory instruction. * * Format: * op * *************************************************************************/ ULONG ParseMemSpec(PUCHAR inString, POPTBLENTRY pEntry, PULONG poffset, PULONG instruction) { *instruction = (OPCODE(pEntry->opCode) + MEM_FUNC(pEntry->funcCode)); return (GOODINSTRUCTION); } /*** ParseJump - parse jump instruction * * Purpose: * Given the users input, create the memory instruction. * * Format: * op Ra,(Rb),hint * op Ra,(Rb) - not really - we just support it here * *************************************************************************/ ULONG ParseJump(PUCHAR inString, POPTBLENTRY pEntry, PULONG poffset, PULONG instruction) { ULONG Ra; ULONG Rb; ULONG hint; ULONG err; Ra = GetIntReg(inString, &inString); if (!TestCharacter(inString, &inString, ',')) return(OPERAND); if (!TestCharacter(inString, &inString, '(')) return(OPERAND); Rb = GetIntReg(inString, &inString); if (!TestCharacter(inString, &inString, ')')) return(OPERAND); if (TestCharacter(inString, &inString, ',')) { // // User is giving us a hint // err = GetValue(inString, &inString, TRUE, WIDTH_HINT, &hint, '\0'); if (err != GOODINSTRUCTION) return err; } else { hint = 0; } if (!TestCharacter(inString, &inString, '\0')) return(EXTRACHARS); *instruction = OPCODE(pEntry->opCode) + JMP_FNC(pEntry->funcCode) + REG_A(Ra) + REG_B(Rb) + HINT(hint); return(GOODINSTRUCTION); } /*** ParseIntBranch - parse integer branch instruction * * Purpose: * Given the users input, create the memory instruction. * * Format: * op Ra,disp * *************************************************************************/ ULONG ParseIntBranch(PUCHAR inString, POPTBLENTRY pEntry, PULONG poffset, PULONG instruction) { ULONG Ra; LONG disp; ULONG err; Ra = GetIntReg(inString, &inString); if (!TestCharacter(inString, &inString, ',')) return(OPERAND); // // the user gives an absolute address; we convert // that to a displacement, which is computed as a // difference off of (pc+1) // GetValue handles both numerics and symbolics // err = GetValue(inString, &inString, TRUE, 32, &disp, '\0'); if (err != GOODINSTRUCTION) return err; // get the relative displacement from the updated pc disp = disp - (LONG)((*poffset)+4); // divide by four disp = disp >> 2; if (!TestCharacter(inString, &inString, '\0')) return(EXTRACHARS); *instruction = OPCODE(pEntry->opCode) + REG_A(Ra) + BR_DISP(disp); return(GOODINSTRUCTION); } /*** ParseFltBranch - parse floating point branch instruction * * Purpose: * Given the users input, create the memory instruction. * * Format: * op Fa,disp * *************************************************************************/ ULONG ParseFltBranch(PUCHAR inString, POPTBLENTRY pEntry, PULONG poffset, PULONG instruction) { ULONG Ra; LONG disp; ULONG err; Ra = GetFltReg(inString, &inString); if (!TestCharacter(inString, &inString, ',')) return(OPERAND); // // the user gives an absolute address; we convert // that to a displacement, which is computed as a // difference off of (pc+1) // GetValue handles both numerics and symbolics // err = GetValue(inString, &inString, TRUE, 32, &disp, '\0'); if (err != GOODINSTRUCTION) return err; // get the relative displacement from the updated pc disp = disp - (LONG)((*poffset)+4); // divide by four disp = disp >> 2; if (!TestCharacter(inString, &inString, '\0')) return(EXTRACHARS); *instruction = OPCODE(pEntry->opCode) + REG_A(Ra) + BR_DISP(disp); return(GOODINSTRUCTION); } /*** ParseIntOp - parse integer operation * * Purpose: * Given the users input, create the memory instruction. * * Format: * op Ra, Rb, Rc * op Ra, #lit, Rc * *************************************************************************/ ULONG ParseIntOp(PUCHAR inString, POPTBLENTRY pEntry, PULONG poffset, PULONG instruction) { ULONG Ra, Rb, Rc; ULONG lit; ULONG Format; // Whether there is a literal or 3rd reg ULONG err; *instruction = OPCODE(pEntry->opCode) + OP_FNC(pEntry->funcCode); Ra = GetIntReg(inString, &inString); if (!TestCharacter(inString, &inString, ',')) return(OPERAND); if (TestCharacter(inString, &inString, '#')) { // // User is giving us a literal value err = GetValue(inString, &inString, TRUE, WIDTH_LIT, &lit, ','); if (err != GOODINSTRUCTION) return err; Format = RBV_LITERAL_FORMAT; } else { // // using a third register value Rb = GetIntReg(inString, &inString); Format = RBV_REGISTER_FORMAT; } if (!TestCharacter(inString, &inString, ',')) return(OPERAND); Rc = GetIntReg(inString, &inString); if (!TestCharacter(inString, &inString, '\0')) return(EXTRACHARS); *instruction = *instruction + REG_A(Ra) + RBV_TYPE(Format) + REG_C(Rc); if (Format == RBV_REGISTER_FORMAT) { *instruction = *instruction + REG_B(Rb); } else { *instruction = *instruction + LIT(lit); } return(GOODINSTRUCTION); } /*** ParsePal - parse PAL code instruction * * Purpose: * Given the users input, create the memory instruction. * * Format: * op * *************************************************************************/ ULONG ParsePal(PUCHAR inString, POPTBLENTRY pEntry, PULONG poffset, PULONG instruction) { if (!TestCharacter(inString, &inString, '\0')) return(EXTRACHARS); *instruction = (OPCODE(pEntry->opCode) + PAL_FNC(pEntry->funcCode)); return (GOODINSTRUCTION); } /*** ParseUnknown - return an error message for an unknown opcode * * Purpose: * return an error message for an unknown opcode * * Format: * ??? * *************************************************************************/ ULONG ParseUnknown(PUCHAR inString, POPTBLENTRY pEntry, PULONG poffset, PULONG instruction) { return(BADOPCODE); }