regop.isa revision 4798:85351424da98
1// Copyright (c) 2007 The Hewlett-Packard Development Company 2// All rights reserved. 3// 4// Redistribution and use of this software in source and binary forms, 5// with or without modification, are permitted provided that the 6// following conditions are met: 7// 8// The software must be used only for Non-Commercial Use which means any 9// use which is NOT directed to receiving any direct monetary 10// compensation for, or commercial advantage from such use. Illustrative 11// examples of non-commercial use are academic research, personal study, 12// teaching, education and corporate research & development. 13// Illustrative examples of commercial use are distributing products for 14// commercial advantage and providing services using the software for 15// commercial advantage. 16// 17// If you wish to use this software or functionality therein that may be 18// covered by patents for commercial use, please contact: 19// Director of Intellectual Property Licensing 20// Office of Strategy and Technology 21// Hewlett-Packard Company 22// 1501 Page Mill Road 23// Palo Alto, California 94304 24// 25// Redistributions of source code must retain the above copyright notice, 26// this list of conditions and the following disclaimer. Redistributions 27// in binary form must reproduce the above copyright notice, this list of 28// conditions and the following disclaimer in the documentation and/or 29// other materials provided with the distribution. Neither the name of 30// the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its 31// contributors may be used to endorse or promote products derived from 32// this software without specific prior written permission. No right of 33// sublicense is granted herewith. Derivatives of the software and 34// output created using the software may be prepared, but only for 35// Non-Commercial Uses. Derivatives of the software may be shared with 36// others provided: (i) the others agree to abide by the list of 37// conditions herein which includes the Non-Commercial Use restrictions; 38// and (ii) such Derivatives of the software include the above copyright 39// notice to acknowledge the contribution from this software where 40// applicable, this list of conditions and the disclaimer below. 41// 42// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 43// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 44// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 45// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 46// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 47// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 48// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 49// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 50// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 51// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 52// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 53// 54// Authors: Gabe Black 55 56////////////////////////////////////////////////////////////////////////// 57// 58// RegOp Microop templates 59// 60////////////////////////////////////////////////////////////////////////// 61 62def template MicroRegOpExecute {{ 63 Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, 64 Trace::InstRecord *traceData) const 65 { 66 Fault fault = NoFault; 67 68 %(op_decl)s; 69 %(op_rd)s; 70 71 if(%(cond_check)s) 72 { 73 %(code)s; 74 %(flag_code)s; 75 } 76 else 77 { 78 %(else_code)s; 79 } 80 81 //Write the resulting state to the execution context 82 if(fault == NoFault) 83 { 84 %(op_wb)s; 85 } 86 return fault; 87 } 88}}; 89 90def template MicroRegOpImmExecute {{ 91 Fault %(class_name)sImm::execute(%(CPU_exec_context)s *xc, 92 Trace::InstRecord *traceData) const 93 { 94 Fault fault = NoFault; 95 96 %(op_decl)s; 97 %(op_rd)s; 98 99 if(%(cond_check)s) 100 { 101 %(code)s; 102 %(flag_code)s; 103 } 104 else 105 { 106 %(else_code)s; 107 } 108 109 //Write the resulting state to the execution context 110 if(fault == NoFault) 111 { 112 %(op_wb)s; 113 } 114 return fault; 115 } 116}}; 117 118def template MicroRegOpDeclare {{ 119 class %(class_name)s : public %(base_class)s 120 { 121 protected: 122 void buildMe(); 123 124 public: 125 %(class_name)s(ExtMachInst _machInst, 126 const char * instMnem, 127 bool isMicro, bool isDelayed, bool isFirst, bool isLast, 128 RegIndex _src1, RegIndex _src2, RegIndex _dest, 129 uint8_t _dataSize, uint16_t _ext); 130 131 %(class_name)s(ExtMachInst _machInst, 132 const char * instMnem, 133 RegIndex _src1, RegIndex _src2, RegIndex _dest, 134 uint8_t _dataSize, uint16_t _ext); 135 136 %(BasicExecDeclare)s 137 }; 138}}; 139 140def template MicroRegOpImmDeclare {{ 141 142 class %(class_name)sImm : public %(base_class)s 143 { 144 protected: 145 void buildMe(); 146 147 public: 148 %(class_name)sImm(ExtMachInst _machInst, 149 const char * instMnem, 150 bool isMicro, bool isDelayed, bool isFirst, bool isLast, 151 RegIndex _src1, uint8_t _imm8, RegIndex _dest, 152 uint8_t _dataSize, uint16_t _ext); 153 154 %(class_name)sImm(ExtMachInst _machInst, 155 const char * instMnem, 156 RegIndex _src1, uint8_t _imm8, RegIndex _dest, 157 uint8_t _dataSize, uint16_t _ext); 158 159 %(BasicExecDeclare)s 160 }; 161}}; 162 163def template MicroRegOpConstructor {{ 164 165 inline void %(class_name)s::buildMe() 166 { 167 %(constructor)s; 168 } 169 170 inline %(class_name)s::%(class_name)s( 171 ExtMachInst machInst, const char * instMnem, 172 RegIndex _src1, RegIndex _src2, RegIndex _dest, 173 uint8_t _dataSize, uint16_t _ext) : 174 %(base_class)s(machInst, "%(mnemonic)s", instMnem, 175 false, false, false, false, 176 _src1, _src2, _dest, _dataSize, _ext, 177 %(op_class)s) 178 { 179 buildMe(); 180 } 181 182 inline %(class_name)s::%(class_name)s( 183 ExtMachInst machInst, const char * instMnem, 184 bool isMicro, bool isDelayed, bool isFirst, bool isLast, 185 RegIndex _src1, RegIndex _src2, RegIndex _dest, 186 uint8_t _dataSize, uint16_t _ext) : 187 %(base_class)s(machInst, "%(mnemonic)s", instMnem, 188 isMicro, isDelayed, isFirst, isLast, 189 _src1, _src2, _dest, _dataSize, _ext, 190 %(op_class)s) 191 { 192 buildMe(); 193 } 194}}; 195 196def template MicroRegOpImmConstructor {{ 197 198 inline void %(class_name)sImm::buildMe() 199 { 200 %(constructor)s; 201 } 202 203 inline %(class_name)sImm::%(class_name)sImm( 204 ExtMachInst machInst, const char * instMnem, 205 RegIndex _src1, uint8_t _imm8, RegIndex _dest, 206 uint8_t _dataSize, uint16_t _ext) : 207 %(base_class)s(machInst, "%(mnemonic)s", instMnem, 208 false, false, false, false, 209 _src1, _imm8, _dest, _dataSize, _ext, 210 %(op_class)s) 211 { 212 buildMe(); 213 } 214 215 inline %(class_name)sImm::%(class_name)sImm( 216 ExtMachInst machInst, const char * instMnem, 217 bool isMicro, bool isDelayed, bool isFirst, bool isLast, 218 RegIndex _src1, uint8_t _imm8, RegIndex _dest, 219 uint8_t _dataSize, uint16_t _ext) : 220 %(base_class)s(machInst, "%(mnemonic)s", instMnem, 221 isMicro, isDelayed, isFirst, isLast, 222 _src1, _imm8, _dest, _dataSize, _ext, 223 %(op_class)s) 224 { 225 buildMe(); 226 } 227}}; 228 229let {{ 230 class X86MicroMeta(type): 231 def __new__(mcls, name, bases, dict): 232 abstract = False 233 if "abstract" in dict: 234 abstract = dict['abstract'] 235 del dict['abstract'] 236 237 cls = type.__new__(mcls, name, bases, dict) 238 if not abstract: 239 allClasses[name] = cls 240 return cls 241 242 class XXX86Microop(object): 243 __metaclass__ = X86MicroMeta 244 abstract = True 245 246 class RegOp(X86Microop): 247 abstract = True 248 def __init__(self, dest, src1, src2, flags, dataSize): 249 self.dest = dest 250 self.src1 = src1 251 self.src2 = src2 252 self.flags = flags 253 self.dataSize = dataSize 254 if flags is None: 255 self.ext = 0 256 else: 257 if not isinstance(flags, (list, tuple)): 258 raise Exception, "flags must be a list or tuple of flags" 259 self.ext = " | ".join(flags) 260 self.className += "Flags" 261 262 def getAllocator(self, *microFlags): 263 allocator = '''new %(class_name)s(machInst, mnemonic 264 %(flags)s, %(src1)s, %(src2)s, %(dest)s, 265 %(dataSize)s, %(ext)s)''' % { 266 "class_name" : self.className, 267 "flags" : self.microFlagsText(microFlags), 268 "src1" : self.src1, "src2" : self.src2, 269 "dest" : self.dest, 270 "dataSize" : self.dataSize, 271 "ext" : self.ext} 272 return allocator 273 274 class RegOpImm(X86Microop): 275 abstract = True 276 def __init__(self, dest, src1, imm8, flags, dataSize): 277 self.dest = dest 278 self.src1 = src1 279 self.imm8 = imm8 280 self.flags = flags 281 self.dataSize = dataSize 282 if flags is None: 283 self.ext = 0 284 else: 285 if not isinstance(flags, (list, tuple)): 286 raise Exception, "flags must be a list or tuple of flags" 287 self.ext = " | ".join(flags) 288 self.className += "Flags" 289 290 def getAllocator(self, *microFlags): 291 allocator = '''new %(class_name)s(machInst, mnemonic 292 %(flags)s, %(src1)s, %(imm8)s, %(dest)s, 293 %(dataSize)s, %(ext)s)''' % { 294 "class_name" : self.className, 295 "flags" : self.microFlagsText(microFlags), 296 "src1" : self.src1, "imm8" : self.imm8, 297 "dest" : self.dest, 298 "dataSize" : self.dataSize, 299 "ext" : self.ext} 300 return allocator 301}}; 302 303let {{ 304 305 # Make these empty strings so that concatenating onto 306 # them will always work. 307 header_output = "" 308 decoder_output = "" 309 exec_output = "" 310 311 # A function which builds the C++ classes that implement the microops 312 def setUpMicroRegOp(name, Name, base, code, flagCode = "", condCheck = "true", elseCode = ";"): 313 global header_output 314 global decoder_output 315 global exec_output 316 global microopClasses 317 318 iop = InstObjParams(name, Name, base, 319 {"code" : code, 320 "flag_code" : flagCode, 321 "cond_check" : condCheck, 322 "else_code" : elseCode}) 323 header_output += MicroRegOpDeclare.subst(iop) 324 decoder_output += MicroRegOpConstructor.subst(iop) 325 exec_output += MicroRegOpExecute.subst(iop) 326 327 328 checkCCFlagBits = "checkCondition(ccFlagBits)" 329 genCCFlagBits = \ 330 "ccFlagBits = genFlags(ccFlagBits, ext, DestReg, SrcReg1, op2);" 331 genCCFlagBitsSub = \ 332 "ccFlagBits = genFlags(ccFlagBits, ext, DestReg, SrcReg1, ~op2, true);" 333 genCCFlagBitsLogic = ''' 334 //Don't have genFlags handle the OF or CF bits 335 uint64_t mask = CFBit | OFBit; 336 ccFlagBits = genFlags(ccFlagBits, ext & ~mask, DestReg, SrcReg1, op2); 337 //If a logic microop wants to set these, it wants to set them to 0. 338 ccFlagBits &= ~(CFBit & ext); 339 ccFlagBits &= ~(OFBit & ext); 340 ''' 341 342 343 # This creates a python representations of a microop which are a cross 344 # product of reg/immediate and flag/no flag versions. 345 def defineMicroRegOp(mnemonic, code, flagCode=genCCFlagBits, \ 346 cc=False, elseCode=";"): 347 Name = mnemonic 348 name = mnemonic.lower() 349 350 # Find op2 in each of the instruction definitions. Create two versions 351 # of the code, one with an integer operand, and one with an immediate 352 # operand. 353 matcher = re.compile("op2(?P<typeQual>\\.\\w+)?") 354 regCode = matcher.sub("SrcReg2", code) 355 immCode = matcher.sub("imm8", code) 356 357 if not cc: 358 condCode = "true" 359 else: 360 flagCode = "" 361 condCode = checkCCFlagBits 362 363 regFlagCode = matcher.sub("SrcReg2", flagCode) 364 immFlagCode = matcher.sub("imm8", flagCode) 365 366 class RegOpChild(RegOp): 367 mnemonic = name 368 className = Name 369 def __init__(self, dest, src1, src2, \ 370 flags=None, dataSize="env.dataSize"): 371 super(RegOpChild, self).__init__(dest, src1, src2, \ 372 flags, dataSize) 373 374 microopClasses[name] = RegOpChild 375 376 setUpMicroRegOp(name, Name, "X86ISA::RegOp", regCode); 377 setUpMicroRegOp(name, Name + "Flags", "X86ISA::RegOp", regCode, 378 flagCode=regFlagCode, condCheck=condCode, elseCode=elseCode); 379 380 class RegOpChildImm(RegOpImm): 381 mnemonic = name + 'i' 382 className = Name + 'Imm' 383 def __init__(self, dest, src1, src2, \ 384 flags=None, dataSize="env.dataSize"): 385 super(RegOpChildImm, self).__init__(dest, src1, src2, \ 386 flags, dataSize) 387 388 microopClasses[name + 'i'] = RegOpChildImm 389 390 setUpMicroRegOp(name + "i", Name + "Imm", "X86ISA::RegOpImm", immCode); 391 setUpMicroRegOp(name + "i", Name + "ImmFlags", "X86ISA::RegOpImm", immCode, 392 flagCode=immFlagCode, condCheck=condCode, elseCode=elseCode); 393 394 # This has it's own function because Wr ops have implicit destinations 395 def defineMicroRegOpWr(mnemonic, code, elseCode=";"): 396 Name = mnemonic 397 name = mnemonic.lower() 398 399 # Find op2 in each of the instruction definitions. Create two versions 400 # of the code, one with an integer operand, and one with an immediate 401 # operand. 402 matcher = re.compile("op2(?P<typeQual>\\.\\w+)?") 403 regCode = matcher.sub("SrcReg2", code) 404 immCode = matcher.sub("imm8", code) 405 406 class RegOpChild(RegOp): 407 mnemonic = name 408 className = Name 409 def __init__(self, src1, src2, flags=None, dataSize="env.dataSize"): 410 super(RegOpChild, self).__init__("NUM_INTREGS", src1, src2, flags, dataSize) 411 412 microopClasses[name] = RegOpChild 413 414 setUpMicroRegOp(name, Name, "X86ISA::RegOp", regCode); 415 setUpMicroRegOp(name, Name + "Flags", "X86ISA::RegOp", regCode, 416 condCheck = checkCCFlagBits, elseCode = elseCode); 417 418 class RegOpChildImm(RegOpImm): 419 mnemonic = name + 'i' 420 className = Name + 'Imm' 421 def __init__(self, src1, src2, flags=None, dataSize="env.dataSize"): 422 super(RegOpChildImm, self).__init__("NUM_INTREGS", src1, src2, flags, dataSize) 423 424 microopClasses[name + 'i'] = RegOpChildImm 425 426 setUpMicroRegOp(name + 'i', Name + "Imm", "X86ISA::RegOpImm", immCode); 427 setUpMicroRegOp(name + 'i', Name + "ImmFlags", "X86ISA::RegOpImm", immCode, 428 condCheck = checkCCFlagBits, elseCode = elseCode); 429 430 # This has it's own function because Rd ops don't always have two parameters 431 def defineMicroRegOpRd(mnemonic, code): 432 Name = mnemonic 433 name = mnemonic.lower() 434 435 class RegOpChild(RegOp): 436 def __init__(self, dest, src1 = "NUM_INTREGS", dataSize="env.dataSize"): 437 super(RegOpChild, self).__init__(dest, src1, "NUM_INTREGS", None, dataSize) 438 self.className = Name 439 self.mnemonic = name 440 441 microopClasses[name] = RegOpChild 442 443 setUpMicroRegOp(name, Name, "X86ISA::RegOp", code); 444 445 def defineMicroRegOpImm(mnemonic, code): 446 Name = mnemonic 447 name = mnemonic.lower() 448 449 class RegOpChild(RegOpImm): 450 def __init__(self, dest, src1, src2, dataSize="env.dataSize"): 451 super(RegOpChild, self).__init__(dest, src1, src2, None, dataSize) 452 self.className = Name 453 self.mnemonic = name 454 455 microopClasses[name] = RegOpChild 456 457 setUpMicroRegOp(name, Name, "X86ISA::RegOpImm", code); 458 459 defineMicroRegOp('Add', 'DestReg = merge(DestReg, SrcReg1 + op2, dataSize)') 460 defineMicroRegOp('Or', 'DestReg = merge(DestReg, SrcReg1 | op2, dataSize)', 461 flagCode = genCCFlagBitsLogic) 462 defineMicroRegOp('Adc', ''' 463 CCFlagBits flags = ccFlagBits; 464 DestReg = merge(DestReg, SrcReg1 + op2 + flags.CF, dataSize); 465 ''') 466 defineMicroRegOp('Sbb', ''' 467 CCFlagBits flags = ccFlagBits; 468 DestReg = merge(DestReg, SrcReg1 - op2 - flags.CF, dataSize); 469 ''', flagCode = genCCFlagBitsSub) 470 defineMicroRegOp('And', \ 471 'DestReg = merge(DestReg, SrcReg1 & op2, dataSize)', \ 472 flagCode = genCCFlagBitsLogic) 473 defineMicroRegOp('Sub', \ 474 'DestReg = merge(DestReg, SrcReg1 - op2, dataSize)', \ 475 flagCode = genCCFlagBitsSub) 476 defineMicroRegOp('Xor', \ 477 'DestReg = merge(DestReg, SrcReg1 ^ op2, dataSize)', \ 478 flagCode = genCCFlagBitsLogic) 479 defineMicroRegOp('Mul1s', \ 480 'DestReg = merge(DestReg, DestReg * op2, dataSize)') 481 defineMicroRegOp('Mov', 'DestReg = merge(SrcReg1, op2, dataSize)', 482 elseCode='DestReg=DestReg;', cc=True) 483 484 # Shift instructions 485 defineMicroRegOp('Sll', ''' 486 uint8_t shiftAmt = (op2 & ((dataSize == 8) ? mask(6) : mask(5))); 487 DestReg = merge(DestReg, SrcReg1 << shiftAmt, dataSize); 488 ''') 489 defineMicroRegOp('Srl', ''' 490 uint8_t shiftAmt = (op2 & ((dataSize == 8) ? mask(6) : mask(5))); 491 // Because what happens to the bits shift -in- on a right shift 492 // is not defined in the C/C++ standard, we have to mask them out 493 // to be sure they're zero. 494 uint64_t logicalMask = mask(dataSize * 8 - shiftAmt); 495 DestReg = merge(DestReg, (SrcReg1 >> shiftAmt) & logicalMask, dataSize); 496 ''') 497 defineMicroRegOp('Sra', ''' 498 uint8_t shiftAmt = (op2 & ((dataSize == 8) ? mask(6) : mask(5))); 499 // Because what happens to the bits shift -in- on a right shift 500 // is not defined in the C/C++ standard, we have to sign extend 501 // them manually to be sure. 502 uint64_t arithMask = 503 -bits(op2, dataSize * 8 - 1) << (dataSize * 8 - shiftAmt); 504 DestReg = merge(DestReg, (SrcReg1 >> shiftAmt) | arithMask, dataSize); 505 ''') 506 defineMicroRegOp('Ror', ''' 507 uint8_t shiftAmt = 508 (op2 & ((dataSize == 8) ? mask(6) : mask(5))); 509 if(shiftAmt) 510 { 511 uint64_t top = SrcReg1 << (dataSize * 8 - shiftAmt); 512 uint64_t bottom = bits(SrcReg1, dataSize * 8, shiftAmt); 513 DestReg = merge(DestReg, top | bottom, dataSize); 514 } 515 else 516 DestReg = DestReg; 517 ''') 518 defineMicroRegOp('Rcr', ''' 519 uint8_t shiftAmt = 520 (op2 & ((dataSize == 8) ? mask(6) : mask(5))); 521 if(shiftAmt) 522 { 523 CCFlagBits flags = ccFlagBits; 524 uint64_t top = flags.CF << (dataSize * 8 - shiftAmt); 525 if(shiftAmt > 1) 526 top |= SrcReg1 << (dataSize * 8 - shiftAmt - 1); 527 uint64_t bottom = bits(SrcReg1, dataSize * 8, shiftAmt); 528 DestReg = merge(DestReg, top | bottom, dataSize); 529 } 530 else 531 DestReg = DestReg; 532 ''') 533 defineMicroRegOp('Rol', ''' 534 uint8_t shiftAmt = 535 (op2 & ((dataSize == 8) ? mask(6) : mask(5))); 536 if(shiftAmt) 537 { 538 uint64_t top = SrcReg1 << shiftAmt; 539 uint64_t bottom = 540 bits(SrcReg1, dataSize * 8 - 1, dataSize * 8 - shiftAmt); 541 DestReg = merge(DestReg, top | bottom, dataSize); 542 } 543 else 544 DestReg = DestReg; 545 ''') 546 defineMicroRegOp('Rcl', ''' 547 uint8_t shiftAmt = 548 (op2 & ((dataSize == 8) ? mask(6) : mask(5))); 549 if(shiftAmt) 550 { 551 CCFlagBits flags = ccFlagBits; 552 uint64_t top = SrcReg1 << shiftAmt; 553 uint64_t bottom = flags.CF << (shiftAmt - 1); 554 if(shiftAmt > 1) 555 bottom |= 556 bits(SrcReg1, dataSize * 8 - 1, 557 dataSize * 8 - shiftAmt + 1); 558 DestReg = merge(DestReg, top | bottom, dataSize); 559 } 560 else 561 DestReg = DestReg; 562 ''') 563 564 defineMicroRegOpWr('Wrip', 'RIP = SrcReg1 + op2', elseCode="RIP = RIP;") 565 566 defineMicroRegOpRd('Rdip', 'DestReg = RIP') 567 568 defineMicroRegOpImm('Sext', ''' 569 IntReg val = SrcReg1; 570 int sign_bit = bits(val, imm8-1, imm8-1); 571 val = sign_bit ? (val | ~mask(imm8)) : val; 572 DestReg = merge(DestReg, val, dataSize);''') 573 574 defineMicroRegOpImm('Zext', 'DestReg = bits(SrcReg1, imm8-1, 0);') 575}}; 576