1// -*- mode:c++ -*- 2 3// Copyright (c) 2007 The Hewlett-Packard Development Company 4// All rights reserved. 5// 6// The license below extends only to copyright in the software and shall 7// not be construed as granting a license to any other intellectual 8// property including but not limited to intellectual property relating 9// to a hardware implementation of the functionality of the software 10// licensed hereunder. You may use the software subject to the license 11// terms below provided that you ensure that this notice is replicated 12// unmodified and in its entirety in all distributions of the software, 13// modified or unmodified, in source code or in binary form. 14// 15// Redistribution and use in source and binary forms, with or without 16// modification, are permitted provided that the following conditions are 17// met: redistributions of source code must retain the above copyright 18// notice, this list of conditions and the following disclaimer; 19// redistributions in binary form must reproduce the above copyright 20// notice, this list of conditions and the following disclaimer in the 21// documentation and/or other materials provided with the distribution; 22// neither the name of the copyright holders nor the names of its 23// contributors may be used to endorse or promote products derived from 24// this software without specific prior written permission. 25// 26// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 27// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 28// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 29// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 30// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 31// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 32// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 33// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 34// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 35// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 36// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37// 38// Authors: Gabe Black 39 40////////////////////////////////////////////////////////////////////////////// 41// 42// Architecture independent 43// 44 45// Execute method for macroops. 46def template MacroExecPanic {{ 47 Fault execute(ExecContext *, Trace::InstRecord *) const 48 { 49 panic("Tried to execute macroop directly!"); 50 return NoFault; 51 } 52}}; 53 54output header {{ 55 56 // Base class for combinationally generated macroops 57 class Macroop : public X86ISA::MacroopBase 58 { 59 public: 60 Macroop(const char *mnem, ExtMachInst _machInst, 61 uint32_t _numMicroops, X86ISA::EmulEnv _env) 62 : MacroopBase(mnem, _machInst, _numMicroops, _env) 63 {} 64 65 Fault 66 execute(ExecContext *, Trace::InstRecord *) const 67 { 68 panic("Tried to execute macroop directly!"); 69 } 70 }; 71}}; 72 73////////////////////////////////////////////////////////////////////////////// 74// 75// X86 specific 76// 77////////////////////////////////////////////////////////////////////////////// 78 79// Basic instruction class declaration template. 80def template MacroDeclare {{ 81 namespace X86Macroop 82 { 83 /** 84 * Static instruction class for "%(mnemonic)s". 85 */ 86 class %(class_name)s : public %(base_class)s 87 { 88 private: 89 %(declareLabels)s 90 public: 91 // Constructor. 92 %(class_name)s(ExtMachInst machInst, X86ISA::EmulEnv _env); 93 94 std::string 95 generateDisassembly(Addr pc, const SymbolTable *symtab) const; 96 }; 97 } 98}}; 99 100def template MacroDisassembly {{ 101 std::string 102 X86Macroop::%(class_name)s::generateDisassembly(Addr pc, 103 const SymbolTable *symtab) const 104 { 105 std::stringstream out; 106 out << mnemonic << "\t"; 107 108 int regSize = %(regSize)s; 109 %(disassembly)s 110 // Shut up gcc. 111 regSize = regSize; 112 return out.str(); 113 } 114}}; 115 116// Basic instruction class constructor template. 117def template MacroConstructor {{ 118 X86Macroop::%(class_name)s::%(class_name)s( 119 ExtMachInst machInst, EmulEnv _env) 120 : %(base_class)s("%(mnemonic)s", machInst, %(num_microops)s, _env) 121 { 122 %(adjust_env)s; 123 %(adjust_imm)s; 124 %(adjust_disp)s; 125 %(init_env)s; 126 %(constructor)s; 127 const char *macrocodeBlock = "%(class_name)s"; 128 //alloc_microops is the code that sets up the microops 129 //array in the parent class. 130 %(alloc_microops)s; 131 } 132}}; 133 134let {{ 135 from micro_asm import Combinational_Macroop, Rom_Macroop 136 class X86Macroop(Combinational_Macroop): 137 def add_microop(self, mnemonic, microop): 138 microop.mnemonic = mnemonic 139 microop.micropc = len(self.microops) 140 self.microops.append(microop) 141 def setAdjustEnv(self, val): 142 self.adjust_env = val 143 def adjustImm(self, val): 144 self.adjust_imm += val 145 def adjustDisp(self, val): 146 self.adjust_disp += val 147 def serializeBefore(self): 148 self.serialize_before = True 149 def serializeAfter(self): 150 self.serialize_after = True 151 152 def function_call(self): 153 self.function_call = True 154 def function_return(self): 155 self.function_return = True 156 157 def __init__(self, name): 158 super(X86Macroop, self).__init__(name) 159 self.directives = { 160 "adjust_env" : self.setAdjustEnv, 161 "adjust_imm" : self.adjustImm, 162 "adjust_disp" : self.adjustDisp, 163 "serialize_before" : self.serializeBefore, 164 "serialize_after" : self.serializeAfter, 165 "function_call" : self.function_call, 166 "function_return" : self.function_return 167 } 168 self.declared = False 169 self.adjust_env = "" 170 self.init_env = "" 171 self.adjust_imm = ''' 172 uint64_t adjustedImm = IMMEDIATE; 173 //This is to pacify gcc in case the immediate isn't used. 174 adjustedImm = adjustedImm; 175 ''' 176 self.adjust_disp = ''' 177 uint64_t adjustedDisp = DISPLACEMENT; 178 //This is to pacify gcc in case the displacement isn't used. 179 adjustedDisp = adjustedDisp; 180 ''' 181 self.serialize_before = False 182 self.serialize_after = False 183 self.function_call = False 184 self.function_return = False 185 186 def getAllocator(self, env): 187 return "new X86Macroop::%s(machInst, %s)" % \ 188 (self.name, env.getAllocator()) 189 def getMnemonic(self): 190 mnemonic = self.name.lower() 191 mnemonic = re.match(r'[^_]*', mnemonic).group(0) 192 return mnemonic 193 def getDeclaration(self): 194 #FIXME This first parameter should be the mnemonic. I need to 195 #write some code which pulls that out 196 declareLabels = "" 197 for (label, microop) in self.labels.items(): 198 declareLabels += "const static uint64_t label_%s = %d;\n" \ 199 % (label, microop.micropc) 200 iop = InstObjParams(self.getMnemonic(), self.name, "Macroop", 201 {"code" : "", 202 "declareLabels" : declareLabels 203 }) 204 return MacroDeclare.subst(iop); 205 def getDefinition(self, env): 206 #FIXME This first parameter should be the mnemonic. I need to 207 #write some code which pulls that out 208 numMicroops = len(self.microops) 209 allocMicroops = '' 210 micropc = 0 211 for op in self.microops: 212 flags = ["IsMicroop"] 213 if micropc == 0: 214 flags.append("IsFirstMicroop") 215 216 if self.serialize_before: 217 flags.append("IsSerializing") 218 flags.append("IsSerializeBefore") 219 220 if micropc == numMicroops - 1: 221 flags.append("IsLastMicroop") 222 223 if self.serialize_after: 224 flags.append("IsSerializing") 225 flags.append("IsSerializeAfter") 226 227 if self.function_call: 228 flags.append("IsCall") 229 flags.append("IsUncondControl") 230 if self.function_return: 231 flags.append("IsReturn") 232 flags.append("IsUncondControl") 233 else: 234 flags.append("IsDelayedCommit") 235 236 allocMicroops += \ 237 "microops[%d] = %s;\n" % \ 238 (micropc, op.getAllocator(flags)) 239 micropc += 1 240 if env.useStackSize: 241 useStackSize = "true" 242 else: 243 useStackSize = "false" 244 if env.memoryInst: 245 memoryInst = "true" 246 else: 247 memoryInst = "false" 248 regSize = '''(%s || (env.base == INTREG_RSP && %s) ? 249 env.stackSize : 250 env.dataSize)''' % (useStackSize, memoryInst) 251 iop = InstObjParams(self.getMnemonic(), self.name, "Macroop", 252 {"code" : "", "num_microops" : numMicroops, 253 "alloc_microops" : allocMicroops, 254 "adjust_env" : self.adjust_env, 255 "adjust_imm" : self.adjust_imm, 256 "adjust_disp" : self.adjust_disp, 257 "disassembly" : env.disassembly, 258 "regSize" : regSize, 259 "init_env" : self.initEnv}) 260 return MacroConstructor.subst(iop) + \ 261 MacroDisassembly.subst(iop); 262}}; 263 264let {{ 265 class EmulEnv(object): 266 def __init__(self): 267 self.reg = "0" 268 self.regUsed = False 269 self.regm = "0" 270 self.regmUsed = False 271 self.seg = "SEGMENT_REG_DS" 272 self.size = None 273 self.addressSize = "ADDRSIZE" 274 self.dataSize = "OPSIZE" 275 self.stackSize = "STACKSIZE" 276 self.doModRM = False 277 self.disassembly = "" 278 self.firstArgument = True 279 self.useStackSize = False 280 self.memoryInst = False 281 282 def addToDisassembly(self, code): 283 if not self.firstArgument: 284 self.disassembly += "out << \", \";\n" 285 self.firstArgument = False 286 self.disassembly += code 287 288 def getAllocator(self): 289 if self.size == 'b': 290 self.dataSize = 1 291 elif self.size == 'd': 292 self.dataSize = 4 293 #This is for "double plus" which is normally a double word unless 294 #the REX W bit is set, in which case it's a quad word. It's used 295 #for some SSE instructions. 296 elif self.size == 'dp': 297 self.dataSize = "(REX_W ? 8 : 4)" 298 elif self.size == 'q': 299 self.dataSize = 8 300 elif self.size == 'v': 301 self.dataSize = "OPSIZE" 302 elif self.size == 'w': 303 self.dataSize = 2 304 elif self.size == 'z': 305 self.dataSize = "((OPSIZE == 8) ? 4 : OPSIZE)" 306 elif self.size: 307 raise Exception, "Unrecognized size type %s!" % self.size 308 return '''EmulEnv(%(reg)s, 309 %(regm)s, 310 %(dataSize)s, 311 %(addressSize)s, 312 %(stackSize)s)''' % \ 313 self.__dict__ 314 315 def addReg(self, reg): 316 if not self.regUsed: 317 self.reg = reg 318 self.regUsed = True 319 elif not self.regmUsed: 320 self.regm = reg 321 self.regmUsed = True 322 else: 323 raise Exception, "EmulEnv is out of register specialization spots." 324 def setSize(self, size): 325 if not self.size: 326 self.size = size 327 else: 328 if self.size != size: 329 raise Exception, "Conflicting register sizes %s and %s!" %\ 330 (self.size, size) 331}}; 332 333let {{ 334 doModRMString = "env.doModRM(machInst);\n" 335 noModRMString = "env.setSeg(machInst);\n" 336 def genMacroop(Name, env): 337 blocks = OutputBlocks() 338 if not Name in macroopDict: 339 raise Exception, "Unrecognized instruction: %s" % Name 340 macroop = macroopDict[Name] 341 if not macroop.declared: 342 if env.doModRM: 343 macroop.initEnv = doModRMString 344 else: 345 macroop.initEnv = noModRMString 346 blocks.header_output = macroop.getDeclaration() 347 blocks.decoder_output = macroop.getDefinition(env) 348 macroop.declared = True 349 blocks.decode_block = "return %s;\n" % macroop.getAllocator(env) 350 return blocks 351}}; 352