|  | // -*- mode:c++ -*- | 
|  |  | 
|  | // Copyright (c) 2007 The Hewlett-Packard Development Company | 
|  | // All rights reserved. | 
|  | // | 
|  | // The license below extends only to copyright in the software and shall | 
|  | // not be construed as granting a license to any other intellectual | 
|  | // property including but not limited to intellectual property relating | 
|  | // to a hardware implementation of the functionality of the software | 
|  | // licensed hereunder.  You may use the software subject to the license | 
|  | // terms below provided that you ensure that this notice is replicated | 
|  | // unmodified and in its entirety in all distributions of the software, | 
|  | // modified or unmodified, in source code or in binary form. | 
|  | // | 
|  | // Redistribution and use in source and binary forms, with or without | 
|  | // modification, are permitted provided that the following conditions are | 
|  | // met: redistributions of source code must retain the above copyright | 
|  | // notice, this list of conditions and the following disclaimer; | 
|  | // redistributions in binary form must reproduce the above copyright | 
|  | // notice, this list of conditions and the following disclaimer in the | 
|  | // documentation and/or other materials provided with the distribution; | 
|  | // neither the name of the copyright holders nor the names of its | 
|  | // contributors may be used to endorse or promote products derived from | 
|  | // this software without specific prior written permission. | 
|  | // | 
|  | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 
|  | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 
|  | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 
|  | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 
|  | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 
|  | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 
|  | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 
|  | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 
|  | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
|  | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
|  | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
|  | // | 
|  | // Authors: Gabe Black | 
|  |  | 
|  | ////////////////////////////////////////////////////////////////////////////// | 
|  | // | 
|  | //  Architecture independent | 
|  | // | 
|  |  | 
|  | // Execute method for macroops. | 
|  | def template MacroExecPanic {{ | 
|  | Fault execute(%(CPU_exec_context)s *, Trace::InstRecord *) const | 
|  | { | 
|  | panic("Tried to execute macroop directly!"); | 
|  | return NoFault; | 
|  | } | 
|  | }}; | 
|  |  | 
|  | output header {{ | 
|  |  | 
|  | // Base class for combinationally generated macroops | 
|  | class Macroop : public X86ISA::MacroopBase | 
|  | { | 
|  | public: | 
|  | Macroop(const char *mnem, ExtMachInst _machInst, | 
|  | uint32_t _numMicroops, X86ISA::EmulEnv _env) | 
|  | : MacroopBase(mnem, _machInst, _numMicroops, _env) | 
|  | {} | 
|  | %(MacroExecPanic)s | 
|  | }; | 
|  | }}; | 
|  |  | 
|  | ////////////////////////////////////////////////////////////////////////////// | 
|  | // | 
|  | //  X86 specific | 
|  | // | 
|  | ////////////////////////////////////////////////////////////////////////////// | 
|  |  | 
|  | // Basic instruction class declaration template. | 
|  | def template MacroDeclare {{ | 
|  | namespace X86Macroop | 
|  | { | 
|  | /** | 
|  | * Static instruction class for "%(mnemonic)s". | 
|  | */ | 
|  | class %(class_name)s : public %(base_class)s | 
|  | { | 
|  | private: | 
|  | %(declareLabels)s | 
|  | public: | 
|  | // Constructor. | 
|  | %(class_name)s(ExtMachInst machInst, X86ISA::EmulEnv _env); | 
|  |  | 
|  | std::string | 
|  | generateDisassembly(Addr pc, const SymbolTable *symtab) const; | 
|  | }; | 
|  | } | 
|  | }}; | 
|  |  | 
|  | def template MacroDisassembly {{ | 
|  | std::string | 
|  | X86Macroop::%(class_name)s::generateDisassembly(Addr pc, | 
|  | const SymbolTable *symtab) const | 
|  | { | 
|  | std::stringstream out; | 
|  | out << mnemonic << "\t"; | 
|  |  | 
|  | int regSize = %(regSize)s; | 
|  | %(disassembly)s | 
|  | // Shut up gcc. | 
|  | regSize = regSize; | 
|  | return out.str(); | 
|  | } | 
|  | }}; | 
|  |  | 
|  | // Basic instruction class constructor template. | 
|  | def template MacroConstructor {{ | 
|  | X86Macroop::%(class_name)s::%(class_name)s( | 
|  | ExtMachInst machInst, EmulEnv _env) | 
|  | : %(base_class)s("%(mnemonic)s", machInst, %(num_microops)s, _env) | 
|  | { | 
|  | %(adjust_env)s; | 
|  | %(adjust_imm)s; | 
|  | %(adjust_disp)s; | 
|  | %(init_env)s; | 
|  | %(constructor)s; | 
|  | const char *macrocodeBlock = "%(class_name)s"; | 
|  | //alloc_microops is the code that sets up the microops | 
|  | //array in the parent class. | 
|  | %(alloc_microops)s; | 
|  | } | 
|  | }}; | 
|  |  | 
|  | let {{ | 
|  | from micro_asm import Combinational_Macroop, Rom_Macroop | 
|  | class X86Macroop(Combinational_Macroop): | 
|  | def add_microop(self, mnemonic, microop): | 
|  | microop.mnemonic = mnemonic | 
|  | microop.micropc = len(self.microops) | 
|  | self.microops.append(microop) | 
|  | def setAdjustEnv(self, val): | 
|  | self.adjust_env = val | 
|  | def adjustImm(self, val): | 
|  | self.adjust_imm += val | 
|  | def adjustDisp(self, val): | 
|  | self.adjust_disp += val | 
|  | def serializing(self): | 
|  | self.serializing = True | 
|  |  | 
|  | def function_call(self): | 
|  | self.function_call = True | 
|  | def function_return(self): | 
|  | self.function_return = True | 
|  |  | 
|  | def __init__(self, name): | 
|  | super(X86Macroop, self).__init__(name) | 
|  | self.directives = { | 
|  | "adjust_env" : self.setAdjustEnv, | 
|  | "adjust_imm" : self.adjustImm, | 
|  | "adjust_disp" : self.adjustDisp, | 
|  | "serializing" : self.serializing, | 
|  | "function_call" : self.function_call, | 
|  | "function_return" : self.function_return | 
|  | } | 
|  | self.declared = False | 
|  | self.adjust_env = "" | 
|  | self.init_env = "" | 
|  | self.adjust_imm = ''' | 
|  | uint64_t adjustedImm = IMMEDIATE; | 
|  | //This is to pacify gcc in case the immediate isn't used. | 
|  | adjustedImm = adjustedImm; | 
|  | ''' | 
|  | self.adjust_disp = ''' | 
|  | uint64_t adjustedDisp = DISPLACEMENT; | 
|  | //This is to pacify gcc in case the displacement isn't used. | 
|  | adjustedDisp = adjustedDisp; | 
|  | ''' | 
|  | self.serializing = False | 
|  | self.function_call = False | 
|  | self.function_return = False | 
|  |  | 
|  | def getAllocator(self, env): | 
|  | return "new X86Macroop::%s(machInst, %s)" % \ | 
|  | (self.name, env.getAllocator()) | 
|  | def getMnemonic(self): | 
|  | mnemonic = self.name.lower() | 
|  | mnemonic = re.match(r'[^_]*', mnemonic).group(0) | 
|  | return mnemonic | 
|  | def getDeclaration(self): | 
|  | #FIXME This first parameter should be the mnemonic. I need to | 
|  | #write some code which pulls that out | 
|  | declareLabels = "" | 
|  | for (label, microop) in self.labels.items(): | 
|  | declareLabels += "const static uint64_t label_%s = %d;\n" \ | 
|  | % (label, microop.micropc) | 
|  | iop = InstObjParams(self.getMnemonic(), self.name, "Macroop", | 
|  | {"code" : "", | 
|  | "declareLabels" : declareLabels | 
|  | }) | 
|  | return MacroDeclare.subst(iop); | 
|  | def getDefinition(self, env): | 
|  | #FIXME This first parameter should be the mnemonic. I need to | 
|  | #write some code which pulls that out | 
|  | numMicroops = len(self.microops) | 
|  | allocMicroops = '' | 
|  | micropc = 0 | 
|  | for op in self.microops: | 
|  | flags = ["IsMicroop"] | 
|  | if micropc == numMicroops - 1: | 
|  | flags.append("IsLastMicroop") | 
|  |  | 
|  | if self.serializing: | 
|  | flags.append("IsSerializing") | 
|  | flags.append("IsSerializeAfter") | 
|  |  | 
|  | if self.function_call: | 
|  | flags.append("IsCall") | 
|  | if self.function_return: | 
|  | flags.append("IsReturn") | 
|  | else: | 
|  | flags.append("IsDelayedCommit") | 
|  | if micropc == 0: | 
|  | flags.append("IsFirstMicroop") | 
|  | allocMicroops += \ | 
|  | "microops[%d] = %s;\n" % \ | 
|  | (micropc, op.getAllocator(flags)) | 
|  | micropc += 1 | 
|  | if env.useStackSize: | 
|  | useStackSize = "true" | 
|  | else: | 
|  | useStackSize = "false" | 
|  | if env.memoryInst: | 
|  | memoryInst = "true" | 
|  | else: | 
|  | memoryInst = "false" | 
|  | regSize = '''(%s || (env.base == INTREG_RSP && %s) ? | 
|  | env.stackSize : | 
|  | env.dataSize)''' % (useStackSize, memoryInst) | 
|  | iop = InstObjParams(self.getMnemonic(), self.name, "Macroop", | 
|  | {"code" : "", "num_microops" : numMicroops, | 
|  | "alloc_microops" : allocMicroops, | 
|  | "adjust_env" : self.adjust_env, | 
|  | "adjust_imm" : self.adjust_imm, | 
|  | "adjust_disp" : self.adjust_disp, | 
|  | "disassembly" : env.disassembly, | 
|  | "regSize" : regSize, | 
|  | "init_env" : self.initEnv}) | 
|  | return MacroConstructor.subst(iop) + \ | 
|  | MacroDisassembly.subst(iop); | 
|  | }}; | 
|  |  | 
|  | let {{ | 
|  | class EmulEnv(object): | 
|  | def __init__(self): | 
|  | self.reg = "0" | 
|  | self.regUsed = False | 
|  | self.regm = "0" | 
|  | self.regmUsed = False | 
|  | self.seg = "SEGMENT_REG_DS" | 
|  | self.size = None | 
|  | self.addressSize = "ADDRSIZE" | 
|  | self.dataSize = "OPSIZE" | 
|  | self.stackSize = "STACKSIZE" | 
|  | self.doModRM = False | 
|  | self.disassembly = "" | 
|  | self.firstArgument = True | 
|  | self.useStackSize = False | 
|  | self.memoryInst = False | 
|  |  | 
|  | def addToDisassembly(self, code): | 
|  | if not self.firstArgument: | 
|  | self.disassembly += "out << \", \";\n" | 
|  | self.firstArgument = False | 
|  | self.disassembly += code | 
|  |  | 
|  | def getAllocator(self): | 
|  | if self.size == 'b': | 
|  | self.dataSize = 1 | 
|  | elif self.size == 'd': | 
|  | self.dataSize = 4 | 
|  | #This is for "double plus" which is normally a double word unless | 
|  | #the REX W bit is set, in which case it's a quad word. It's used | 
|  | #for some SSE instructions. | 
|  | elif self.size == 'dp': | 
|  | self.dataSize = "(REX_W ? 8 : 4)" | 
|  | elif self.size == 'q': | 
|  | self.dataSize = 8 | 
|  | elif self.size == 'v': | 
|  | self.dataSize = "OPSIZE" | 
|  | elif self.size == 'w': | 
|  | self.dataSize = 2 | 
|  | elif self.size == 'z': | 
|  | self.dataSize = "((OPSIZE == 8) ? 4 : OPSIZE)" | 
|  | elif self.size: | 
|  | raise Exception, "Unrecognized size type %s!" % self.size | 
|  | return '''EmulEnv(%(reg)s, | 
|  | %(regm)s, | 
|  | %(dataSize)s, | 
|  | %(addressSize)s, | 
|  | %(stackSize)s)''' % \ | 
|  | self.__dict__ | 
|  |  | 
|  | def addReg(self, reg): | 
|  | if not self.regUsed: | 
|  | self.reg = reg | 
|  | self.regUsed = True | 
|  | elif not self.regmUsed: | 
|  | self.regm = reg | 
|  | self.regmUsed = True | 
|  | else: | 
|  | raise Exception, "EmulEnv is out of register specialization spots." | 
|  | def setSize(self, size): | 
|  | if not self.size: | 
|  | self.size = size | 
|  | else: | 
|  | if self.size != size: | 
|  | raise Exception, "Conflicting register sizes %s and %s!" %\ | 
|  | (self.size, size) | 
|  | }}; | 
|  |  | 
|  | let {{ | 
|  | doModRMString = "env.doModRM(machInst);\n" | 
|  | noModRMString = "env.setSeg(machInst);\n" | 
|  | def genMacroop(Name, env): | 
|  | blocks = OutputBlocks() | 
|  | if not macroopDict.has_key(Name): | 
|  | raise Exception, "Unrecognized instruction: %s" % Name | 
|  | macroop = macroopDict[Name] | 
|  | if not macroop.declared: | 
|  | if env.doModRM: | 
|  | macroop.initEnv = doModRMString | 
|  | else: | 
|  | macroop.initEnv = noModRMString | 
|  | blocks.header_output = macroop.getDeclaration() | 
|  | blocks.decoder_output = macroop.getDefinition(env) | 
|  | macroop.declared = True | 
|  | blocks.decode_block = "return %s;\n" % macroop.getAllocator(env) | 
|  | return blocks | 
|  | }}; |