regop.isa revision 5076:956a475dddea
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 DPRINTF(X86, "The data size is %d\n", dataSize); 69 %(op_decl)s; 70 %(op_rd)s; 71 72 if(%(cond_check)s) 73 { 74 %(code)s; 75 %(flag_code)s; 76 } 77 else 78 { 79 %(else_code)s; 80 } 81 82 //Write the resulting state to the execution context 83 if(fault == NoFault) 84 { 85 %(op_wb)s; 86 } 87 return fault; 88 } 89}}; 90 91def template MicroRegOpImmExecute {{ 92 Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, 93 Trace::InstRecord *traceData) const 94 { 95 Fault fault = NoFault; 96 97 %(op_decl)s; 98 %(op_rd)s; 99 100 if(%(cond_check)s) 101 { 102 %(code)s; 103 %(flag_code)s; 104 } 105 else 106 { 107 %(else_code)s; 108 } 109 110 //Write the resulting state to the execution context 111 if(fault == NoFault) 112 { 113 %(op_wb)s; 114 } 115 return fault; 116 } 117}}; 118 119def template MicroRegOpDeclare {{ 120 class %(class_name)s : public %(base_class)s 121 { 122 protected: 123 void buildMe(); 124 125 public: 126 %(class_name)s(ExtMachInst _machInst, 127 const char * instMnem, 128 bool isMicro, bool isDelayed, bool isFirst, bool isLast, 129 RegIndex _src1, RegIndex _src2, RegIndex _dest, 130 uint8_t _dataSize, uint16_t _ext); 131 132 %(class_name)s(ExtMachInst _machInst, 133 const char * instMnem, 134 RegIndex _src1, RegIndex _src2, RegIndex _dest, 135 uint8_t _dataSize, uint16_t _ext); 136 137 %(BasicExecDeclare)s 138 }; 139}}; 140 141def template MicroRegOpImmDeclare {{ 142 143 class %(class_name)s : public %(base_class)s 144 { 145 protected: 146 void buildMe(); 147 148 public: 149 %(class_name)s(ExtMachInst _machInst, 150 const char * instMnem, 151 bool isMicro, bool isDelayed, bool isFirst, bool isLast, 152 RegIndex _src1, uint16_t _imm8, RegIndex _dest, 153 uint8_t _dataSize, uint16_t _ext); 154 155 %(class_name)s(ExtMachInst _machInst, 156 const char * instMnem, 157 RegIndex _src1, uint16_t _imm8, RegIndex _dest, 158 uint8_t _dataSize, uint16_t _ext); 159 160 %(BasicExecDeclare)s 161 }; 162}}; 163 164def template MicroRegOpConstructor {{ 165 166 inline void %(class_name)s::buildMe() 167 { 168 %(constructor)s; 169 } 170 171 inline %(class_name)s::%(class_name)s( 172 ExtMachInst machInst, const char * instMnem, 173 RegIndex _src1, RegIndex _src2, RegIndex _dest, 174 uint8_t _dataSize, uint16_t _ext) : 175 %(base_class)s(machInst, "%(mnemonic)s", instMnem, 176 false, false, false, false, 177 _src1, _src2, _dest, _dataSize, _ext, 178 %(op_class)s) 179 { 180 buildMe(); 181 } 182 183 inline %(class_name)s::%(class_name)s( 184 ExtMachInst machInst, const char * instMnem, 185 bool isMicro, bool isDelayed, bool isFirst, bool isLast, 186 RegIndex _src1, RegIndex _src2, RegIndex _dest, 187 uint8_t _dataSize, uint16_t _ext) : 188 %(base_class)s(machInst, "%(mnemonic)s", instMnem, 189 isMicro, isDelayed, isFirst, isLast, 190 _src1, _src2, _dest, _dataSize, _ext, 191 %(op_class)s) 192 { 193 buildMe(); 194 } 195}}; 196 197def template MicroRegOpImmConstructor {{ 198 199 inline void %(class_name)s::buildMe() 200 { 201 %(constructor)s; 202 } 203 204 inline %(class_name)s::%(class_name)s( 205 ExtMachInst machInst, const char * instMnem, 206 RegIndex _src1, uint16_t _imm8, RegIndex _dest, 207 uint8_t _dataSize, uint16_t _ext) : 208 %(base_class)s(machInst, "%(mnemonic)s", instMnem, 209 false, false, false, false, 210 _src1, _imm8, _dest, _dataSize, _ext, 211 %(op_class)s) 212 { 213 buildMe(); 214 } 215 216 inline %(class_name)s::%(class_name)s( 217 ExtMachInst machInst, const char * instMnem, 218 bool isMicro, bool isDelayed, bool isFirst, bool isLast, 219 RegIndex _src1, uint16_t _imm8, RegIndex _dest, 220 uint8_t _dataSize, uint16_t _ext) : 221 %(base_class)s(machInst, "%(mnemonic)s", instMnem, 222 isMicro, isDelayed, isFirst, isLast, 223 _src1, _imm8, _dest, _dataSize, _ext, 224 %(op_class)s) 225 { 226 buildMe(); 227 } 228}}; 229 230output header {{ 231 void 232 divide(uint64_t dividend, uint64_t divisor, 233 uint64_t "ient, uint64_t &remainder); 234}}; 235 236output decoder {{ 237 void 238 divide(uint64_t dividend, uint64_t divisor, 239 uint64_t "ient, uint64_t &remainder) 240 { 241 //Check for divide by zero. 242 if (divisor == 0) 243 panic("Divide by zero!\\n"); 244 //If the divisor is bigger than the dividend, don't do anything. 245 if (divisor <= dividend) { 246 //Shift the divisor so it's msb lines up with the dividend. 247 int dividendMsb = findMsbSet(dividend); 248 int divisorMsb = findMsbSet(divisor); 249 int shift = dividendMsb - divisorMsb; 250 divisor <<= shift; 251 //Compute what we'll add to the quotient if the divisor isn't 252 //now larger than the dividend. 253 uint64_t quotientBit = 1; 254 quotientBit <<= shift; 255 //If we need to step back a bit (no pun intended) because the 256 //divisor got too to large, do that here. This is the "or two" 257 //part of one or two bit division. 258 if (divisor > dividend) { 259 quotientBit >>= 1; 260 divisor >>= 1; 261 } 262 //Decrement the remainder and increment the quotient. 263 quotient += quotientBit; 264 remainder -= divisor; 265 } 266 } 267}}; 268 269let {{ 270 # Make these empty strings so that concatenating onto 271 # them will always work. 272 header_output = "" 273 decoder_output = "" 274 exec_output = "" 275 276 immTemplates = ( 277 MicroRegOpImmDeclare, 278 MicroRegOpImmConstructor, 279 MicroRegOpImmExecute) 280 281 regTemplates = ( 282 MicroRegOpDeclare, 283 MicroRegOpConstructor, 284 MicroRegOpExecute) 285 286 class RegOpMeta(type): 287 def buildCppClasses(self, name, Name, suffix, \ 288 code, flag_code, cond_check, else_code): 289 290 # Globals to stick the output in 291 global header_output 292 global decoder_output 293 global exec_output 294 295 # Stick all the code together so it can be searched at once 296 allCode = "|".join((code, flag_code, cond_check, else_code)) 297 298 # If op2 is used anywhere, make register and immediate versions 299 # of this code. 300 matcher = re.compile("(?<!\\w)(?P<prefix>s?)op2(?P<typeQual>\\.\\w+)?") 301 match = matcher.search(allCode) 302 if match: 303 typeQual = "" 304 if match.group("typeQual"): 305 typeQual = match.group("typeQual") 306 src2_name = "%spsrc2%s" % (match.group("prefix"), typeQual) 307 self.buildCppClasses(name, Name, suffix, 308 matcher.sub(src2_name, code), 309 matcher.sub(src2_name, flag_code), 310 matcher.sub(src2_name, cond_check), 311 matcher.sub(src2_name, else_code)) 312 self.buildCppClasses(name + "i", Name, suffix + "Imm", 313 matcher.sub("imm8", code), 314 matcher.sub("imm8", flag_code), 315 matcher.sub("imm8", cond_check), 316 matcher.sub("imm8", else_code)) 317 return 318 319 # If there's something optional to do with flags, generate 320 # a version without it and fix up this version to use it. 321 if flag_code is not "" or cond_check is not "true": 322 self.buildCppClasses(name, Name, suffix, 323 code, "", "true", else_code) 324 suffix = "Flags" + suffix 325 326 # If psrc1 or psrc2 is used, we need to actually insert code to 327 # compute it. 328 matcher = re.compile("(?<!\w)psrc1(?!\w)") 329 if matcher.search(allCode): 330 code = "uint64_t psrc1 = pick(SrcReg1, 0, dataSize);" + code 331 matcher = re.compile("(?<!\w)psrc2(?!\w)") 332 if matcher.search(allCode): 333 code = "uint64_t psrc2 = pick(SrcReg2, 1, dataSize);" + code 334 # Also make available versions which do sign extension 335 matcher = re.compile("(?<!\w)spsrc1(?!\w)") 336 if matcher.search(allCode): 337 code = "int64_t spsrc1 = signedPick(SrcReg1, 0, dataSize);" + code 338 matcher = re.compile("(?<!\w)spsrc2(?!\w)") 339 if matcher.search(allCode): 340 code = "int64_t spsrc2 = signedPick(SrcReg2, 1, dataSize);" + code 341 342 base = "X86ISA::RegOp" 343 344 # If imm8 shows up in the code, use the immediate templates, if 345 # not, hopefully the register ones will be correct. 346 templates = regTemplates 347 matcher = re.compile("(?<!\w)imm8(?!\w)") 348 if matcher.search(allCode): 349 base += "Imm" 350 templates = immTemplates 351 352 # Get everything ready for the substitution 353 iop = InstObjParams(name, Name + suffix, base, 354 {"code" : code, 355 "flag_code" : flag_code, 356 "cond_check" : cond_check, 357 "else_code" : else_code}) 358 359 # Generate the actual code (finally!) 360 header_output += templates[0].subst(iop) 361 decoder_output += templates[1].subst(iop) 362 exec_output += templates[2].subst(iop) 363 364 365 def __new__(mcls, Name, bases, dict): 366 abstract = False 367 name = Name.lower() 368 if "abstract" in dict: 369 abstract = dict['abstract'] 370 del dict['abstract'] 371 372 cls = super(RegOpMeta, mcls).__new__(mcls, Name, bases, dict) 373 if not abstract: 374 cls.className = Name 375 cls.base_mnemonic = name 376 code = cls.code 377 flag_code = cls.flag_code 378 cond_check = cls.cond_check 379 else_code = cls.else_code 380 381 # Set up the C++ classes 382 mcls.buildCppClasses(cls, name, Name, "", 383 code, flag_code, cond_check, else_code) 384 385 # Hook into the microassembler dict 386 global microopClasses 387 microopClasses[name] = cls 388 389 allCode = "|".join((code, flag_code, cond_check, else_code)) 390 391 # If op2 is used anywhere, make register and immediate versions 392 # of this code. 393 matcher = re.compile("op2(?P<typeQual>\\.\\w+)?") 394 if matcher.search(allCode): 395 microopClasses[name + 'i'] = cls 396 return cls 397 398 399 class RegOp(X86Microop): 400 __metaclass__ = RegOpMeta 401 # This class itself doesn't act as a microop 402 abstract = True 403 404 # Default template parameter values 405 flag_code = "" 406 cond_check = "true" 407 else_code = ";" 408 409 def __init__(self, dest, src1, op2, flags = None, dataSize = "env.dataSize"): 410 self.dest = dest 411 self.src1 = src1 412 self.op2 = op2 413 self.flags = flags 414 self.dataSize = dataSize 415 if flags is None: 416 self.ext = 0 417 else: 418 if not isinstance(flags, (list, tuple)): 419 raise Exception, "flags must be a list or tuple of flags" 420 self.ext = " | ".join(flags) 421 self.className += "Flags" 422 423 def getAllocator(self, *microFlags): 424 className = self.className 425 if self.mnemonic == self.base_mnemonic + 'i': 426 className += "Imm" 427 allocator = '''new %(class_name)s(machInst, mnemonic 428 %(flags)s, %(src1)s, %(op2)s, %(dest)s, 429 %(dataSize)s, %(ext)s)''' % { 430 "class_name" : className, 431 "flags" : self.microFlagsText(microFlags), 432 "src1" : self.src1, "op2" : self.op2, 433 "dest" : self.dest, 434 "dataSize" : self.dataSize, 435 "ext" : self.ext} 436 return allocator 437 438 class LogicRegOp(RegOp): 439 abstract = True 440 flag_code = ''' 441 //Don't have genFlags handle the OF or CF bits 442 uint64_t mask = CFBit | OFBit; 443 ccFlagBits = genFlags(ccFlagBits, ext & ~mask, DestReg, psrc1, op2); 444 //If a logic microop wants to set these, it wants to set them to 0. 445 ccFlagBits &= ~(CFBit & ext); 446 ccFlagBits &= ~(OFBit & ext); 447 ''' 448 449 class FlagRegOp(RegOp): 450 abstract = True 451 flag_code = \ 452 "ccFlagBits = genFlags(ccFlagBits, ext, DestReg, psrc1, op2);" 453 454 class SubRegOp(RegOp): 455 abstract = True 456 flag_code = \ 457 "ccFlagBits = genFlags(ccFlagBits, ext, DestReg, psrc1, ~op2, true);" 458 459 class CondRegOp(RegOp): 460 abstract = True 461 cond_check = "checkCondition(ccFlagBits)" 462 463 class RdRegOp(RegOp): 464 abstract = True 465 def __init__(self, dest, src1=None, dataSize="env.dataSize"): 466 if not src1: 467 src1 = dest 468 super(RdRegOp, self).__init__(dest, src1, "NUM_INTREGS", None, dataSize) 469 470 class WrRegOp(RegOp): 471 abstract = True 472 def __init__(self, src1, src2, flags=None, dataSize="env.dataSize"): 473 super(WrRegOp, self).__init__("NUM_INTREGS", src1, src2, flags, dataSize) 474 475 class Add(FlagRegOp): 476 code = 'DestReg = merge(DestReg, psrc1 + op2, dataSize);' 477 478 class Or(LogicRegOp): 479 code = 'DestReg = merge(DestReg, psrc1 | op2, dataSize);' 480 481 class Adc(FlagRegOp): 482 code = ''' 483 CCFlagBits flags = ccFlagBits; 484 DestReg = merge(DestReg, psrc1 + op2 + flags.CF, dataSize); 485 ''' 486 487 class Sbb(SubRegOp): 488 code = ''' 489 CCFlagBits flags = ccFlagBits; 490 DestReg = merge(DestReg, psrc1 - op2 - flags.CF, dataSize); 491 ''' 492 493 class And(LogicRegOp): 494 code = 'DestReg = merge(DestReg, psrc1 & op2, dataSize)' 495 496 class Sub(SubRegOp): 497 code = 'DestReg = merge(DestReg, psrc1 - op2, dataSize)' 498 499 class Xor(LogicRegOp): 500 code = 'DestReg = merge(DestReg, psrc1 ^ op2, dataSize)' 501 502 # Neither of these is quite correct because it assumes that right shifting 503 # a signed or unsigned value does sign or zero extension respectively. 504 # The C standard says that what happens on a right shift with a 1 in the 505 # MSB position is undefined. On x86 and under likely most compilers the 506 # "right thing" happens, but this isn't a guarantee. 507 class Mul1s(WrRegOp): 508 code = ''' 509 ProdLow = psrc1 * op2; 510 int halfSize = (dataSize * 8) / 2; 511 int64_t spsrc1_h = spsrc1 >> halfSize; 512 int64_t spsrc1_l = spsrc1 & mask(halfSize); 513 int64_t spsrc2_h = sop2 >> halfSize; 514 int64_t spsrc2_l = sop2 & mask(halfSize); 515 ProdHi = ((spsrc1_l * spsrc2_h + spsrc1_h * spsrc2_l + 516 ((spsrc1_l * spsrc2_l) >> halfSize)) >> halfSize) + 517 spsrc1_h * spsrc2_h; 518 ''' 519 520 class Mul1u(WrRegOp): 521 code = ''' 522 ProdLow = psrc1 * op2; 523 int halfSize = (dataSize * 8) / 2; 524 uint64_t psrc1_h = psrc1 >> halfSize; 525 uint64_t psrc1_l = psrc1 & mask(halfSize); 526 uint64_t psrc2_h = op2 >> halfSize; 527 uint64_t psrc2_l = op2 & mask(halfSize); 528 ProdHi = ((psrc1_l * psrc2_h + psrc1_h * psrc2_l + 529 ((psrc1_l * psrc2_l) >> halfSize)) >> halfSize) + 530 psrc1_h * psrc2_h; 531 ''' 532 533 class Mulel(RdRegOp): 534 code = 'DestReg = merge(SrcReg1, ProdLow, dataSize);' 535 536 class Muleh(RdRegOp): 537 def __init__(self, dest, src1=None, flags=None, dataSize="env.dataSize"): 538 if not src1: 539 src1 = dest 540 super(RdRegOp, self).__init__(dest, src1, "NUM_INTREGS", flags, dataSize) 541 code = 'DestReg = merge(SrcReg1, ProdHi, dataSize);' 542 flag_code = ''' 543 if (ProdHi) 544 ccFlagBits = ccFlagBits | (ext & (CFBit | OFBit | ECFBit)); 545 else 546 ccFlagBits = ccFlagBits & ~(ext & (CFBit | OFBit | ECFBit)); 547 ''' 548 549 # One or two bit divide 550 class Div1(WrRegOp): 551 code = ''' 552 //These are temporaries so that modifying them later won't make 553 //the ISA parser think they're also sources. 554 uint64_t quotient = 0; 555 uint64_t remainder = psrc1; 556 //Similarly, this is a temporary so changing it doesn't make it 557 //a source. 558 uint64_t divisor = op2; 559 //This is a temporary just for consistency and clarity. 560 uint64_t dividend = remainder; 561 //Do the division. 562 divide(dividend, divisor, quotient, remainder); 563 //Record the final results. 564 Remainder = remainder; 565 Quotient = quotient; 566 Divisor = divisor; 567 ''' 568 569 # Step divide 570 class Div2(RegOp): 571 code = ''' 572 uint64_t dividend = Remainder; 573 uint64_t divisor = Divisor; 574 uint64_t quotient = Quotient; 575 uint64_t remainder = dividend; 576 int remaining = op2; 577 //If we overshot, do nothing. This lets us unrool division loops a 578 //little. 579 if (remaining) { 580 //Shift in bits from the low order portion of the dividend 581 while(dividend < divisor && remaining) { 582 dividend = (dividend << 1) | bits(SrcReg1, remaining - 1); 583 quotient <<= 1; 584 remaining--; 585 } 586 remainder = dividend; 587 //Do the division. 588 divide(dividend, divisor, quotient, remainder); 589 } 590 //Keep track of how many bits there are still to pull in. 591 DestReg = merge(DestReg, remaining, dataSize); 592 //Record the final results 593 Remainder = remainder; 594 Quotient = quotient; 595 ''' 596 flag_code = ''' 597 if (DestReg == 0) 598 ccFlagBits = ccFlagBits | (ext & EZFBit); 599 else 600 ccFlagBits = ccFlagBits & ~(ext & EZFBit); 601 ''' 602 603 class Divq(RdRegOp): 604 code = 'DestReg = merge(SrcReg1, Quotient, dataSize);' 605 606 class Divr(RdRegOp): 607 code = 'DestReg = merge(SrcReg1, Remainder, dataSize);' 608 609 class Mov(CondRegOp): 610 code = 'DestReg = merge(SrcReg1, op2, dataSize)' 611 else_code = 'DestReg=DestReg;' 612 613 # Shift instructions 614 615 class Sll(RegOp): 616 code = ''' 617 uint8_t shiftAmt = (op2 & ((dataSize == 8) ? mask(6) : mask(5))); 618 DestReg = merge(DestReg, psrc1 << shiftAmt, dataSize); 619 ''' 620 flag_code = ''' 621 // If the shift amount is zero, no flags should be modified. 622 if (shiftAmt) { 623 //Zero out any flags we might modify. This way we only have to 624 //worry about setting them. 625 ccFlagBits = ccFlagBits & ~(ext & (CFBit | ECFBit | OFBit)); 626 int CFBits = 0; 627 //Figure out if we -would- set the CF bits if requested. 628 if (bits(SrcReg1, dataSize * 8 - shiftAmt)) 629 CFBits = 1; 630 //If some combination of the CF bits need to be set, set them. 631 if ((ext & (CFBit | ECFBit)) && CFBits) 632 ccFlagBits = ccFlagBits | (ext & (CFBit | ECFBit)); 633 //Figure out what the OF bit should be. 634 if ((ext & OFBit) && (CFBits ^ bits(DestReg, dataSize * 8 - 1))) 635 ccFlagBits = ccFlagBits | OFBit; 636 //Use the regular mechanisms to calculate the other flags. 637 ccFlagBits = genFlags(ccFlagBits, ext & ~(CFBit | ECFBit | OFBit), 638 DestReg, psrc1, op2); 639 } 640 ''' 641 642 class Srl(RegOp): 643 code = ''' 644 uint8_t shiftAmt = (op2 & ((dataSize == 8) ? mask(6) : mask(5))); 645 // Because what happens to the bits shift -in- on a right shift 646 // is not defined in the C/C++ standard, we have to mask them out 647 // to be sure they're zero. 648 uint64_t logicalMask = mask(dataSize * 8 - shiftAmt); 649 DestReg = merge(DestReg, (psrc1 >> shiftAmt) & logicalMask, dataSize); 650 ''' 651 flag_code = ''' 652 // If the shift amount is zero, no flags should be modified. 653 if (shiftAmt) { 654 //Zero out any flags we might modify. This way we only have to 655 //worry about setting them. 656 ccFlagBits = ccFlagBits & ~(ext & (CFBit | ECFBit | OFBit)); 657 //If some combination of the CF bits need to be set, set them. 658 if ((ext & (CFBit | ECFBit)) && bits(SrcReg1, shiftAmt - 1)) 659 ccFlagBits = ccFlagBits | (ext & (CFBit | ECFBit)); 660 //Figure out what the OF bit should be. 661 if ((ext & OFBit) && bits(SrcReg1, dataSize * 8 - 1)) 662 ccFlagBits = ccFlagBits | OFBit; 663 //Use the regular mechanisms to calculate the other flags. 664 ccFlagBits = genFlags(ccFlagBits, ext & ~(CFBit | ECFBit | OFBit), 665 DestReg, psrc1, op2); 666 } 667 ''' 668 669 class Sra(RegOp): 670 code = ''' 671 uint8_t shiftAmt = (op2 & ((dataSize == 8) ? mask(6) : mask(5))); 672 // Because what happens to the bits shift -in- on a right shift 673 // is not defined in the C/C++ standard, we have to sign extend 674 // them manually to be sure. 675 uint64_t arithMask = 676 -bits(psrc1, dataSize * 8 - 1) << (dataSize * 8 - shiftAmt); 677 DestReg = merge(DestReg, (psrc1 >> shiftAmt) | arithMask, dataSize); 678 ''' 679 flag_code = ''' 680 // If the shift amount is zero, no flags should be modified. 681 if (shiftAmt) { 682 //Zero out any flags we might modify. This way we only have to 683 //worry about setting them. 684 ccFlagBits = ccFlagBits & ~(ext & (CFBit | ECFBit | OFBit)); 685 //If some combination of the CF bits need to be set, set them. 686 if ((ext & (CFBit | ECFBit)) && bits(SrcReg1, shiftAmt - 1)) 687 ccFlagBits = ccFlagBits | (ext & (CFBit | ECFBit)); 688 //Use the regular mechanisms to calculate the other flags. 689 ccFlagBits = genFlags(ccFlagBits, ext & ~(CFBit | ECFBit | OFBit), 690 DestReg, psrc1, op2); 691 } 692 ''' 693 694 class Ror(RegOp): 695 code = ''' 696 uint8_t shiftAmt = 697 (op2 & ((dataSize == 8) ? mask(6) : mask(5))); 698 if(shiftAmt) 699 { 700 uint64_t top = psrc1 << (dataSize * 8 - shiftAmt); 701 uint64_t bottom = bits(psrc1, dataSize * 8, shiftAmt); 702 DestReg = merge(DestReg, top | bottom, dataSize); 703 } 704 else 705 DestReg = DestReg; 706 ''' 707 flag_code = ''' 708 // If the shift amount is zero, no flags should be modified. 709 if (shiftAmt) { 710 //Zero out any flags we might modify. This way we only have to 711 //worry about setting them. 712 ccFlagBits = ccFlagBits & ~(ext & (CFBit | ECFBit | OFBit)); 713 //Find the most and second most significant bits of the result. 714 int msb = bits(DestReg, dataSize * 8 - 1); 715 int smsb = bits(DestReg, dataSize * 8 - 2); 716 //If some combination of the CF bits need to be set, set them. 717 if ((ext & (CFBit | ECFBit)) && msb) 718 ccFlagBits = ccFlagBits | (ext & (CFBit | ECFBit)); 719 //Figure out what the OF bit should be. 720 if ((ext & OFBit) && (msb ^ smsb)) 721 ccFlagBits = ccFlagBits | OFBit; 722 //Use the regular mechanisms to calculate the other flags. 723 ccFlagBits = genFlags(ccFlagBits, ext & ~(CFBit | ECFBit | OFBit), 724 DestReg, psrc1, op2); 725 } 726 ''' 727 728 class Rcr(RegOp): 729 code = ''' 730 uint8_t shiftAmt = 731 (op2 & ((dataSize == 8) ? mask(6) : mask(5))); 732 if(shiftAmt) 733 { 734 CCFlagBits flags = ccFlagBits; 735 uint64_t top = flags.CF << (dataSize * 8 - shiftAmt); 736 if(shiftAmt > 1) 737 top |= psrc1 << (dataSize * 8 - shiftAmt - 1); 738 uint64_t bottom = bits(psrc1, dataSize * 8, shiftAmt); 739 DestReg = merge(DestReg, top | bottom, dataSize); 740 } 741 else 742 DestReg = DestReg; 743 ''' 744 flag_code = ''' 745 // If the shift amount is zero, no flags should be modified. 746 if (shiftAmt) { 747 //Zero out any flags we might modify. This way we only have to 748 //worry about setting them. 749 ccFlagBits = ccFlagBits & ~(ext & (CFBit | ECFBit | OFBit)); 750 //Figure out what the OF bit should be. 751 if ((ext & OFBit) && ((ccFlagBits & CFBit) ^ 752 bits(SrcReg1, dataSize * 8 - 1))) 753 ccFlagBits = ccFlagBits | OFBit; 754 //If some combination of the CF bits need to be set, set them. 755 if ((ext & (CFBit | ECFBit)) && bits(SrcReg1, shiftAmt - 1)) 756 ccFlagBits = ccFlagBits | (ext & (CFBit | ECFBit)); 757 //Use the regular mechanisms to calculate the other flags. 758 ccFlagBits = genFlags(ccFlagBits, ext & ~(CFBit | ECFBit | OFBit), 759 DestReg, psrc1, op2); 760 } 761 ''' 762 763 class Rol(RegOp): 764 code = ''' 765 uint8_t shiftAmt = 766 (op2 & ((dataSize == 8) ? mask(6) : mask(5))); 767 if(shiftAmt) 768 { 769 uint64_t top = psrc1 << shiftAmt; 770 uint64_t bottom = 771 bits(psrc1, dataSize * 8 - 1, dataSize * 8 - shiftAmt); 772 DestReg = merge(DestReg, top | bottom, dataSize); 773 } 774 else 775 DestReg = DestReg; 776 ''' 777 flag_code = ''' 778 // If the shift amount is zero, no flags should be modified. 779 if (shiftAmt) { 780 //Zero out any flags we might modify. This way we only have to 781 //worry about setting them. 782 ccFlagBits = ccFlagBits & ~(ext & (CFBit | ECFBit | OFBit)); 783 //The CF bits, if set, would be set to the lsb of the result. 784 int lsb = DestReg & 0x1; 785 int msb = bits(DestReg, dataSize * 8 - 1); 786 //If some combination of the CF bits need to be set, set them. 787 if ((ext & (CFBit | ECFBit)) && lsb) 788 ccFlagBits = ccFlagBits | (ext & (CFBit | ECFBit)); 789 //Figure out what the OF bit should be. 790 if ((ext & OFBit) && (msb ^ lsb)) 791 ccFlagBits = ccFlagBits | OFBit; 792 //Use the regular mechanisms to calculate the other flags. 793 ccFlagBits = genFlags(ccFlagBits, ext & ~(CFBit | ECFBit | OFBit), 794 DestReg, psrc1, op2); 795 } 796 ''' 797 798 class Rcl(RegOp): 799 code = ''' 800 uint8_t shiftAmt = 801 (op2 & ((dataSize == 8) ? mask(6) : mask(5))); 802 if(shiftAmt) 803 { 804 CCFlagBits flags = ccFlagBits; 805 uint64_t top = psrc1 << shiftAmt; 806 uint64_t bottom = flags.CF << (shiftAmt - 1); 807 if(shiftAmt > 1) 808 bottom |= 809 bits(psrc1, dataSize * 8 - 1, 810 dataSize * 8 - shiftAmt + 1); 811 DestReg = merge(DestReg, top | bottom, dataSize); 812 } 813 else 814 DestReg = DestReg; 815 ''' 816 flag_code = ''' 817 // If the shift amount is zero, no flags should be modified. 818 if (shiftAmt) { 819 //Zero out any flags we might modify. This way we only have to 820 //worry about setting them. 821 ccFlagBits = ccFlagBits & ~(ext & (CFBit | ECFBit | OFBit)); 822 int msb = bits(DestReg, dataSize * 8 - 1); 823 int CFBits = bits(SrcReg1, dataSize * 8 - shiftAmt); 824 //If some combination of the CF bits need to be set, set them. 825 if ((ext & (CFBit | ECFBit)) && CFBits) 826 ccFlagBits = ccFlagBits | (ext & (CFBit | ECFBit)); 827 //Figure out what the OF bit should be. 828 if ((ext & OFBit) && (msb ^ CFBits)) 829 ccFlagBits = ccFlagBits | OFBit; 830 //Use the regular mechanisms to calculate the other flags. 831 ccFlagBits = genFlags(ccFlagBits, ext & ~(CFBit | ECFBit | OFBit), 832 DestReg, psrc1, op2); 833 } 834 ''' 835 836 class Wrip(WrRegOp, CondRegOp): 837 code = 'RIP = psrc1 + op2' 838 else_code="RIP = RIP;" 839 840 class Br(WrRegOp, CondRegOp): 841 code = 'nuIP = psrc1 + op2;' 842 else_code='nuIP = nuIP;' 843 844 class Wruflags(WrRegOp): 845 code = 'ccFlagBits = psrc1 ^ op2' 846 847 class Rdip(RdRegOp): 848 code = 'DestReg = RIP' 849 850 class Ruflags(RdRegOp): 851 code = 'DestReg = ccFlagBits' 852 853 class Ruflag(RegOp): 854 code = ''' 855 int flag = bits(ccFlagBits, imm8 + 0*psrc1); 856 DestReg = merge(DestReg, flag, dataSize); 857 ccFlagBits = (flag == 0) ? (ccFlagBits | EZFBit) : 858 (ccFlagBits & ~EZFBit); 859 ''' 860 def __init__(self, dest, imm, flags=None, \ 861 dataSize="env.dataSize"): 862 super(Ruflag, self).__init__(dest, \ 863 "NUM_INTREGS", imm, flags, dataSize) 864 865 class Sext(RegOp): 866 code = ''' 867 IntReg val = psrc1; 868 int sign_bit = bits(val, imm8-1, imm8-1); 869 uint64_t maskVal = mask(imm8); 870 val = sign_bit ? (val | ~maskVal) : (val & maskVal); 871 DestReg = merge(DestReg, val, dataSize); 872 ''' 873 874 class Zext(RegOp): 875 code = 'DestReg = bits(psrc1, imm8-1, 0);' 876 877 class Compfp(WrRegOp): 878 # This class sets the condition codes in rflags according to the 879 # rules for comparing floating point. 880 code = ''' 881 // ZF PF CF 882 // Unordered 1 1 1 883 // Greater than 0 0 0 884 // Less than 0 0 1 885 // Equal 1 0 0 886 // OF = SF = AF = 0 887 ccFlagBits = ccFlagBits & ~(OFBit | SFBit | AFBit | 888 ZFBit | PFBit | CFBit); 889 if (isnan(FpSrcReg1) || isnan(FpSrcReg2)) 890 ccFlagBits = ccFlagBits | (ZFBit | PFBit | CFBit); 891 else if(FpSrcReg1 < FpSrcReg2) 892 ccFlagBits = ccFlagBits | CFBit; 893 else if(FpSrcReg1 == FpSrcReg2) 894 ccFlagBits = ccFlagBits | ZFBit; 895 ''' 896 897 class Xorfp(RegOp): 898 code = 'FpDestReg.uqw = FpSrcReg1.uqw ^ FpSrcReg2.uqw;' 899 900 class Sqrtfp(RegOp): 901 code = 'FpDestReg = sqrt(FpSrcReg2);' 902 903 class Movfp(CondRegOp): 904 code = 'FpDestReg.uqw = FpSrcReg2.uqw;' 905 else_code = 'FpDestReg.uqw = FpDestReg.uqw;' 906 907 # Conversion microops 908 class ConvOp(RegOp): 909 abstract = True 910 def __init__(self, dest, src1): 911 super(ConvOp, self).__init__(dest, src1, "NUM_INTREGS") 912 913 #FIXME This needs to always use 32 bits unless REX.W is present 914 class cvtf_i2d(ConvOp): 915 code = 'FpDestReg = spsrc1;' 916 917 class cvtf_i2d_hi(ConvOp): 918 code = 'FpDestReg = bits(SrcReg1, 63, 32);' 919 920 class cvtf_d2i(ConvOp): 921 code = ''' 922 int64_t intSrcReg1 = static_cast<int64_t>(FpSrcReg1); 923 DestReg = merge(DestReg, intSrcReg1, dataSize); 924 ''' 925 926 # These need to consider size at some point. They'll always use doubles 927 # for the moment. 928 class addfp(RegOp): 929 code = 'FpDestReg = FpSrcReg1 + FpSrcReg2;' 930 931 class mulfp(RegOp): 932 code = 'FpDestReg = FpSrcReg1 * FpSrcReg2;' 933 934 class divfp(RegOp): 935 code = 'FpDestReg = FpSrcReg1 / FpSrcReg2;' 936 937 class subfp(RegOp): 938 code = 'FpDestReg = FpSrcReg1 - FpSrcReg2;' 939}}; 940