//---------------------------------------------------------------------------- // // Assembe Alpha machine implementation. // // Copyright (C) Microsoft Corporation, 2000. // //---------------------------------------------------------------------------- #include "ntsdp.hpp" #include "alpha_dis.h" #include "alpha_optable.h" #include "alpha_strings.h" #define OPSIZE 16 BOOL TestCharacter (PSTR inString, PSTR *outString, CHAR ch); ULONG GetIntReg(PSTR, PSTR *); ULONG GetFltReg(PSTR, PSTR *); LONG GetValue ( PSTR inString, PSTR *outString, BOOL fSigned, ULONG bitsize ); PSTR SkipWhite(PSTR *); ULONG GetToken(PSTR, PSTR *, PSTR, ULONG); ULONG ParseIntMemory(PSTR, PSTR *, POPTBLENTRY, PULONG64); ULONG ParseFltMemory(PSTR, PSTR *, POPTBLENTRY, PULONG64); ULONG ParseMemSpec(PSTR, PSTR *, POPTBLENTRY, PULONG64); ULONG ParseJump(PSTR, PSTR *, POPTBLENTRY, PULONG64); ULONG ParseIntBranch(PSTR, PSTR *, POPTBLENTRY, PULONG64); ULONG ParseFltBranch(PSTR, PSTR *, POPTBLENTRY, PULONG64); ULONG ParseIntOp(PSTR, PSTR *, POPTBLENTRY, PULONG64); ULONG ParsePal(PSTR, PSTR *, POPTBLENTRY, PULONG64); ULONG ParseUnknown(PSTR, PSTR *, POPTBLENTRY, PULONG64); /*** assem - assemble instruction * * Purpose: * To assemble the instruction pointed by *poffset. * * Input: * pchInput - pointer to string to assemble * * Output: * *poffset - pointer to ADDR at which to assemble * * Exceptions: * error exit: * BADOPCODE - unknown or bad opcode * OPERAND - bad operand * ALIGNMENT - bad byte alignment in operand * DISPLACEMENT - overflow in displacement computation * BADREG - bad register name * EXTRACHARS - extra characters after legal instruction * MEMORY - write failure on assembled instruction * * Notes: * errors are handled by the calling program by outputting * the error string and reprompting the user for the same * instruction. * *************************************************************************/ void AlphaMachineInfo::Assemble (PADDR poffset, PSTR pchInput) { CHAR szOpcode[OPSIZE]; ULONG instruction; 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) error(BADOPCODE); if ((pEntry = findStringEntry(szOpcode)) == (POPTBLENTRY) -1) error(BADOPCODE); if (pEntry->eType == INVALID_ETYPE) { error(BADOPCODE); } // // Use the instruction format specific parser to encode the // instruction plus its operands. // instruction = (*pEntry->parsFunc) (pchInput, &pchInput, pEntry, &(Flat(*poffset))); // // Store the instruction into the target memory location and // increment the instruction pointer. // if (SetMemString(poffset, &instruction, 4) != 4) { error(MEMORY); } Flat(*poffset) += sizeof(ULONG); Off(*poffset) += sizeof(ULONG); } BOOL TestCharacter (PSTR inString, PSTR *outString, CHAR 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 * *************************************************************************/ PCHAR 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" }; PCHAR intRegNames[] = { g_R0, g_R1, g_R2, g_R3, g_R4, g_R5, g_R6, g_R7, g_R8, g_R9, g_R10, g_R11, g_R12, g_R13, g_R14, g_R15, g_R16, g_R17, g_R18, g_R19, g_R20, g_R21, g_R22, g_R23, g_R24, g_R25, g_R26, g_R27, g_R28, g_R29, g_R30, g_R31 }; PCHAR fltRegNames[] = { g_F0, g_F1, g_F2, g_F3, g_F4, g_F5, g_F6, g_F7, g_F8, g_F9, g_F10, g_F11, g_F12, g_F13, g_F14, g_F15, g_F16, g_F17, g_F18, g_F19, g_F20, g_F21, g_F22, g_F23, g_F24, g_F25, g_F26, g_F27, g_F28, g_F29, g_F30, g_F31 }; ULONG GetIntReg (PSTR inString, PSTR *outString) { CHAR szRegOp[5]; ULONG index; if (!GetToken(inString, outString, szRegOp, sizeof(szRegOp))) error(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; } } error(BADREG); return 0; } ULONG GetFltReg (PSTR inString, PSTR *outString) { CHAR szRegOp[5]; ULONG index; if (!GetToken(inString, outString, szRegOp, sizeof(szRegOp))) error(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; } } error(BADREG); return 0; } /*** 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 * * Returns: * value computed from input stream * * Exceptions: * error exit: OVERFLOW - value too large for bitsize * *************************************************************************/ LONG GetValue ( PSTR inString, PSTR *outString, BOOL fSigned, ULONG bitsize ) { ULONGLONG value; inString = SkipWhite(&inString); g_CurCmd = inString; value = GetExpression(); *outString = g_CurCmd; if ((value > (ULONG)(1L << bitsize) - 1) && (!fSigned || (value < (ULONG)(-1L << (bitsize - 1))))) { error(OVERFLOW); } return (LONG)value; } /*** SkipWhite - skip white-space * * Purpose: * To advance g_CurCmd over any spaces or tabs. * * Input: * *g_CurCmd - present command line position * *************************************************************************/ PSTR SkipWhite (PSTR * 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 (PSTR inString, PSTR *outString, PSTR outToken, ULONG maxcnt) { CHAR ch; ULONG count = 0; inString = SkipWhite(&inString); while (count < maxcnt) { ch = (CHAR)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 memory instruction. * * Input: * *inString - present input position * pEntry - pointer into the asmTable for this instr type * * Output: * *outstring - update input position * * Returns: * the instruction. * * Format: * op Ra, disp(Rb) * *************************************************************************/ ULONG ParseIntMemory( PSTR inString, PSTR *outString, POPTBLENTRY pEntry, PULONG64 poffset ) { ULONG instruction; ULONG Ra; ULONG Rb; ULONG disp; Ra = GetIntReg(inString, &inString); if (!TestCharacter(inString, &inString, ',')) error(OPERAND); disp = GetValue(inString, &inString, TRUE, WIDTH_MEM_DISP); if (!TestCharacter(inString, &inString, '(')) error(OPERAND); Rb = GetIntReg(inString, &inString); if (!TestCharacter(inString, &inString, ')')) error(OPERAND); if (!TestCharacter(inString, &inString, '\0')) error(EXTRACHARS); instruction = OPCODE(pEntry->opCode) + REG_A(Ra) + REG_B(Rb) + MEM_DISP(disp); return(instruction); } /*** ParseFltMemory - parse floating point memory instruction * * Purpose: * Given the users input, create the memory instruction. * * Input: * *inString - present input position * pEntry - pointer into the asmTable for this instr type * * Output: * *outstring - update input position * * Returns: * the instruction. * * Format: * op Fa, disp(Rb) * *************************************************************************/ ULONG ParseFltMemory(PSTR inString, PSTR *outString, POPTBLENTRY pEntry, PULONG64 poffset) { ULONG instruction; ULONG Fa; ULONG Rb; ULONG disp; Fa = GetFltReg(inString, &inString); if (!TestCharacter(inString, &inString, ',')) error(OPERAND); disp = (ULONG)GetValue(inString, &inString, TRUE, WIDTH_MEM_DISP); if (!TestCharacter(inString, &inString, '(')) error(OPERAND); Rb = GetIntReg(inString, &inString); if (!TestCharacter(inString, &inString, ')')) error(OPERAND); if (!TestCharacter(inString, &inString, '\0')) error(EXTRACHARS); instruction = OPCODE(pEntry->opCode) + REG_A(Fa) + REG_B(Rb) + MEM_DISP(disp); return(instruction); } /*** ParseMemSpec - parse special memory instruction * * Purpose: * Given the users input, create the memory instruction. * * Input: * *inString - present input position * pEntry - pointer into the asmTable for this instr type * * Output: * *outstring - update input position * * Returns: * the instruction. * * Format: * op * *************************************************************************/ ULONG ParseMemSpec(PSTR inString, PSTR *outString, POPTBLENTRY pEntry, PULONG64 poffset) { return(OPCODE(pEntry->opCode) + MEM_FUNC(pEntry->funcCode)); } /*** ParseJump - parse jump instruction * * Purpose: * Given the users input, create the memory instruction. * * Input: * *inString - present input position * pEntry - pointer into the asmTable for this instr type * * Output: * *outstring - update input position * * Returns: * the instruction. * * Format: * op Ra,(Rb),hint * op Ra,(Rb) - not really - we just support it in ntsd * *************************************************************************/ ULONG ParseJump(PSTR inString, PSTR *outString, POPTBLENTRY pEntry, PULONG64 poffset) { ULONG instruction; ULONG Ra; ULONG Rb; ULONG hint; Ra = GetIntReg(inString, &inString); if (!TestCharacter(inString, &inString, ',')) error(OPERAND); if (!TestCharacter(inString, &inString, '(')) error(OPERAND); Rb = GetIntReg(inString, &inString); if (!TestCharacter(inString, &inString, ')')) error(OPERAND); if (TestCharacter(inString, &inString, ',')) { // // User is giving us a hint // hint = GetValue(inString, &inString, TRUE, WIDTH_HINT); } else { hint = 0; } if (!TestCharacter(inString, &inString, '\0')) error(EXTRACHARS); instruction = OPCODE(pEntry->opCode) + JMP_FNC(pEntry->funcCode) + REG_A(Ra) + REG_B(Rb) + HINT(hint); return(instruction); } /*** ParseIntBranch - parse integer branch instruction * * Purpose: * Given the users input, create the memory instruction. * * Input: * *inString - present input position * pEntry - pointer into the asmTable for this instr type * * Output: * *outstring - update input position * * Returns: * the instruction. * * Format: * op Ra,disp * *************************************************************************/ ULONG ParseIntBranch(PSTR inString, PSTR *outString, POPTBLENTRY pEntry, PULONG64 poffset) { ULONG instruction; ULONG Ra; LONG disp; Ra = GetIntReg(inString, &inString); if (!TestCharacter(inString, &inString, ',')) error(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 // disp = GetValue(inString, &inString, TRUE, 32); // get the relative displacement from the updated pc disp = disp - (LONG)((*poffset)+4); // divide by four disp = disp >> 2; if (!TestCharacter(inString, &inString, '\0')) error(EXTRACHARS); instruction = OPCODE(pEntry->opCode) + REG_A(Ra) + BR_DISP(disp); return(instruction); } /*** ParseFltBranch - parse floating point branch instruction * * Purpose: * Given the users input, create the memory instruction. * * Input: * *inString - present input position * pEntry - pointer into the asmTable for this instr type * * Output: * *outstring - update input position * * Returns: * the instruction. * * Format: * op Fa,disp * *************************************************************************/ ULONG ParseFltBranch(PSTR inString, PSTR *outString, POPTBLENTRY pEntry, PULONG64 poffset) { ULONG instruction; ULONG Ra; LONG disp; Ra = GetFltReg(inString, &inString); if (!TestCharacter(inString, &inString, ',')) error(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 // disp = GetValue(inString, &inString, TRUE, 32); // get the relative displacement from the updated pc disp = disp - (LONG)((*poffset)+4); // divide by four disp = disp >> 2; if (!TestCharacter(inString, &inString, '\0')) error(EXTRACHARS); instruction = OPCODE(pEntry->opCode) + REG_A(Ra) + BR_DISP(disp); return(instruction); } /*** ParseIntOp - parse integer operation * * Purpose: * Given the users input, create the memory instruction. * * Input: * *inString - present input position * pEntry - pointer into the asmTable for this instr type * * Output: * *outstring - update input position * * Returns: * the instruction. * * Format: * op Ra, Rb, Rc * op Ra, #lit, Rc * *************************************************************************/ ULONG ParseIntOp(PSTR inString, PSTR *outString, POPTBLENTRY pEntry, PULONG64 poffset) { ULONG instruction; ULONG Ra, Rb, Rc; ULONG lit; ULONG Format; // Whether there is a literal or 3rd reg instruction = OPCODE(pEntry->opCode) + OP_FNC(pEntry->funcCode); if (pEntry->opCode != SEXT_OP) { Ra = GetIntReg(inString, &inString); if (!TestCharacter(inString, &inString, ',')) error(OPERAND); } else { Ra = 31; } if (TestCharacter(inString, &inString, '#')) { // // User is giving us a literal value lit = GetValue(inString, &inString, TRUE, WIDTH_LIT); Format = RBV_LITERAL_FORMAT; } else { // // using a third register value Rb = GetIntReg(inString, &inString); Format = RBV_REGISTER_FORMAT; } if (!TestCharacter(inString, &inString, ',')) error(OPERAND); Rc = GetIntReg(inString, &inString); if (!TestCharacter(inString, &inString, '\0')) error(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(instruction); } ULONG ParsePal(PSTR inString, PSTR *outString, POPTBLENTRY pEntry, PULONG64 poffset) { if (!TestCharacter(inString, &inString, '\0')) error(EXTRACHARS); return(OPCODE(pEntry->opCode) + PAL_FNC(pEntry->funcCode)); } ULONG ParseUnknown(PSTR inString, PSTR *outString, POPTBLENTRY pEntry, PULONG64 poffset) { dprintf("Unable to assemble %s\n", inString); error(BADOPCODE); return(0); }