regop.isa revision 5788
1// Copyright (c) 2007-2008 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 enum SegmentSelectorCheck { 236 SegNoCheck, SegCSCheck, SegCallGateCheck, SegIntGateCheck, 237 SegSSCheck, SegIretCheck, SegIntCSCheck 238 }; 239 240 enum LongModeDescriptorType { 241 LDT64 = 2, 242 AvailableTSS64 = 9, 243 BusyTSS64 = 0xb, 244 CallGate64 = 0xc, 245 IntGate64 = 0xe, 246 TrapGate64 = 0xf 247 }; 248}}; 249 250output decoder {{ 251 void 252 divide(uint64_t dividend, uint64_t divisor, 253 uint64_t "ient, uint64_t &remainder) 254 { 255 //Check for divide by zero. 256 if (divisor == 0) 257 panic("Divide by zero!\\n"); 258 //If the divisor is bigger than the dividend, don't do anything. 259 if (divisor <= dividend) { 260 //Shift the divisor so it's msb lines up with the dividend. 261 int dividendMsb = findMsbSet(dividend); 262 int divisorMsb = findMsbSet(divisor); 263 int shift = dividendMsb - divisorMsb; 264 divisor <<= shift; 265 //Compute what we'll add to the quotient if the divisor isn't 266 //now larger than the dividend. 267 uint64_t quotientBit = 1; 268 quotientBit <<= shift; 269 //If we need to step back a bit (no pun intended) because the 270 //divisor got too to large, do that here. This is the "or two" 271 //part of one or two bit division. 272 if (divisor > dividend) { 273 quotientBit >>= 1; 274 divisor >>= 1; 275 } 276 //Decrement the remainder and increment the quotient. 277 quotient += quotientBit; 278 remainder -= divisor; 279 } 280 } 281}}; 282 283let {{ 284 # Make these empty strings so that concatenating onto 285 # them will always work. 286 header_output = "" 287 decoder_output = "" 288 exec_output = "" 289 290 immTemplates = ( 291 MicroRegOpImmDeclare, 292 MicroRegOpImmConstructor, 293 MicroRegOpImmExecute) 294 295 regTemplates = ( 296 MicroRegOpDeclare, 297 MicroRegOpConstructor, 298 MicroRegOpExecute) 299 300 class RegOpMeta(type): 301 def buildCppClasses(self, name, Name, suffix, \ 302 code, flag_code, cond_check, else_code): 303 304 # Globals to stick the output in 305 global header_output 306 global decoder_output 307 global exec_output 308 309 # Stick all the code together so it can be searched at once 310 allCode = "|".join((code, flag_code, cond_check, else_code)) 311 312 # If op2 is used anywhere, make register and immediate versions 313 # of this code. 314 matcher = re.compile("(?<!\\w)(?P<prefix>s?)op2(?P<typeQual>\\.\\w+)?") 315 match = matcher.search(allCode) 316 if match: 317 typeQual = "" 318 if match.group("typeQual"): 319 typeQual = match.group("typeQual") 320 src2_name = "%spsrc2%s" % (match.group("prefix"), typeQual) 321 self.buildCppClasses(name, Name, suffix, 322 matcher.sub(src2_name, code), 323 matcher.sub(src2_name, flag_code), 324 matcher.sub(src2_name, cond_check), 325 matcher.sub(src2_name, else_code)) 326 self.buildCppClasses(name + "i", Name, suffix + "Imm", 327 matcher.sub("imm8", code), 328 matcher.sub("imm8", flag_code), 329 matcher.sub("imm8", cond_check), 330 matcher.sub("imm8", else_code)) 331 return 332 333 # If there's something optional to do with flags, generate 334 # a version without it and fix up this version to use it. 335 if flag_code != "" or cond_check != "true": 336 self.buildCppClasses(name, Name, suffix, 337 code, "", "true", else_code) 338 suffix = "Flags" + suffix 339 340 # If psrc1 or psrc2 is used, we need to actually insert code to 341 # compute it. 342 matcher = re.compile("(?<!\w)psrc1(?!\w)") 343 if matcher.search(allCode): 344 code = "uint64_t psrc1 = pick(SrcReg1, 0, dataSize);" + code 345 matcher = re.compile("(?<!\w)psrc2(?!\w)") 346 if matcher.search(allCode): 347 code = "uint64_t psrc2 = pick(SrcReg2, 1, dataSize);" + code 348 # Also make available versions which do sign extension 349 matcher = re.compile("(?<!\w)spsrc1(?!\w)") 350 if matcher.search(allCode): 351 code = "int64_t spsrc1 = signedPick(SrcReg1, 0, dataSize);" + code 352 matcher = re.compile("(?<!\w)spsrc2(?!\w)") 353 if matcher.search(allCode): 354 code = "int64_t spsrc2 = signedPick(SrcReg2, 1, dataSize);" + code 355 356 base = "X86ISA::RegOp" 357 358 # If imm8 shows up in the code, use the immediate templates, if 359 # not, hopefully the register ones will be correct. 360 templates = regTemplates 361 matcher = re.compile("(?<!\w)imm8(?!\w)") 362 if matcher.search(allCode): 363 base += "Imm" 364 templates = immTemplates 365 366 # Get everything ready for the substitution 367 iop = InstObjParams(name, Name + suffix, base, 368 {"code" : code, 369 "flag_code" : flag_code, 370 "cond_check" : cond_check, 371 "else_code" : else_code}) 372 373 # Generate the actual code (finally!) 374 header_output += templates[0].subst(iop) 375 decoder_output += templates[1].subst(iop) 376 exec_output += templates[2].subst(iop) 377 378 379 def __new__(mcls, Name, bases, dict): 380 abstract = False 381 name = Name.lower() 382 if "abstract" in dict: 383 abstract = dict['abstract'] 384 del dict['abstract'] 385 386 cls = super(RegOpMeta, mcls).__new__(mcls, Name, bases, dict) 387 if not abstract: 388 cls.className = Name 389 cls.base_mnemonic = name 390 code = cls.code 391 flag_code = cls.flag_code 392 cond_check = cls.cond_check 393 else_code = cls.else_code 394 395 # Set up the C++ classes 396 mcls.buildCppClasses(cls, name, Name, "", 397 code, flag_code, cond_check, else_code) 398 399 # Hook into the microassembler dict 400 global microopClasses 401 microopClasses[name] = cls 402 403 allCode = "|".join((code, flag_code, cond_check, else_code)) 404 405 # If op2 is used anywhere, make register and immediate versions 406 # of this code. 407 matcher = re.compile("op2(?P<typeQual>\\.\\w+)?") 408 if matcher.search(allCode): 409 microopClasses[name + 'i'] = cls 410 return cls 411 412 413 class RegOp(X86Microop): 414 __metaclass__ = RegOpMeta 415 # This class itself doesn't act as a microop 416 abstract = True 417 418 # Default template parameter values 419 flag_code = "" 420 cond_check = "true" 421 else_code = ";" 422 423 def __init__(self, dest, src1, op2, flags = None, dataSize = "env.dataSize"): 424 self.dest = dest 425 self.src1 = src1 426 self.op2 = op2 427 self.flags = flags 428 self.dataSize = dataSize 429 if flags is None: 430 self.ext = 0 431 else: 432 if not isinstance(flags, (list, tuple)): 433 raise Exception, "flags must be a list or tuple of flags" 434 self.ext = " | ".join(flags) 435 self.className += "Flags" 436 437 def getAllocator(self, *microFlags): 438 className = self.className 439 if self.mnemonic == self.base_mnemonic + 'i': 440 className += "Imm" 441 allocator = '''new %(class_name)s(machInst, macrocodeBlock 442 %(flags)s, %(src1)s, %(op2)s, %(dest)s, 443 %(dataSize)s, %(ext)s)''' % { 444 "class_name" : className, 445 "flags" : self.microFlagsText(microFlags), 446 "src1" : self.src1, "op2" : self.op2, 447 "dest" : self.dest, 448 "dataSize" : self.dataSize, 449 "ext" : self.ext} 450 return allocator 451 452 class LogicRegOp(RegOp): 453 abstract = True 454 flag_code = ''' 455 //Don't have genFlags handle the OF or CF bits 456 uint64_t mask = CFBit | ECFBit | OFBit; 457 ccFlagBits = genFlags(ccFlagBits, ext & ~mask, DestReg, psrc1, op2); 458 //If a logic microop wants to set these, it wants to set them to 0. 459 ccFlagBits &= ~(CFBit & ext); 460 ccFlagBits &= ~(ECFBit & ext); 461 ccFlagBits &= ~(OFBit & ext); 462 ''' 463 464 class FlagRegOp(RegOp): 465 abstract = True 466 flag_code = \ 467 "ccFlagBits = genFlags(ccFlagBits, ext, DestReg, psrc1, op2);" 468 469 class SubRegOp(RegOp): 470 abstract = True 471 flag_code = \ 472 "ccFlagBits = genFlags(ccFlagBits, ext, DestReg, psrc1, ~op2, true);" 473 474 class CondRegOp(RegOp): 475 abstract = True 476 cond_check = "checkCondition(ccFlagBits, ext)" 477 478 class RdRegOp(RegOp): 479 abstract = True 480 def __init__(self, dest, src1=None, dataSize="env.dataSize"): 481 if not src1: 482 src1 = dest 483 super(RdRegOp, self).__init__(dest, src1, "NUM_INTREGS", None, dataSize) 484 485 class WrRegOp(RegOp): 486 abstract = True 487 def __init__(self, src1, src2, flags=None, dataSize="env.dataSize"): 488 super(WrRegOp, self).__init__("NUM_INTREGS", src1, src2, flags, dataSize) 489 490 class Add(FlagRegOp): 491 code = 'DestReg = merge(DestReg, psrc1 + op2, dataSize);' 492 493 class Or(LogicRegOp): 494 code = 'DestReg = merge(DestReg, psrc1 | op2, dataSize);' 495 496 class Adc(FlagRegOp): 497 code = ''' 498 CCFlagBits flags = ccFlagBits; 499 DestReg = merge(DestReg, psrc1 + op2 + flags.cf, dataSize); 500 ''' 501 502 class Sbb(SubRegOp): 503 code = ''' 504 CCFlagBits flags = ccFlagBits; 505 DestReg = merge(DestReg, psrc1 - op2 - flags.cf, dataSize); 506 ''' 507 508 class And(LogicRegOp): 509 code = 'DestReg = merge(DestReg, psrc1 & op2, dataSize)' 510 511 class Sub(SubRegOp): 512 code = 'DestReg = merge(DestReg, psrc1 - op2, dataSize)' 513 514 class Xor(LogicRegOp): 515 code = 'DestReg = merge(DestReg, psrc1 ^ op2, dataSize)' 516 517 # Neither of these is quite correct because it assumes that right shifting 518 # a signed or unsigned value does sign or zero extension respectively. 519 # The C standard says that what happens on a right shift with a 1 in the 520 # MSB position is undefined. On x86 and under likely most compilers the 521 # "right thing" happens, but this isn't a guarantee. 522 class Mul1s(WrRegOp): 523 code = ''' 524 ProdLow = psrc1 * op2; 525 int halfSize = (dataSize * 8) / 2; 526 int64_t spsrc1_h = spsrc1 >> halfSize; 527 int64_t spsrc1_l = spsrc1 & mask(halfSize); 528 int64_t spsrc2_h = sop2 >> halfSize; 529 int64_t spsrc2_l = sop2 & mask(halfSize); 530 ProdHi = ((spsrc1_l * spsrc2_h + spsrc1_h * spsrc2_l + 531 ((spsrc1_l * spsrc2_l) >> halfSize)) >> halfSize) + 532 spsrc1_h * spsrc2_h; 533 ''' 534 535 class Mul1u(WrRegOp): 536 code = ''' 537 ProdLow = psrc1 * op2; 538 int halfSize = (dataSize * 8) / 2; 539 uint64_t psrc1_h = psrc1 >> halfSize; 540 uint64_t psrc1_l = psrc1 & mask(halfSize); 541 uint64_t psrc2_h = op2 >> halfSize; 542 uint64_t psrc2_l = op2 & mask(halfSize); 543 ProdHi = ((psrc1_l * psrc2_h + psrc1_h * psrc2_l + 544 ((psrc1_l * psrc2_l) >> halfSize)) >> halfSize) + 545 psrc1_h * psrc2_h; 546 ''' 547 548 class Mulel(RdRegOp): 549 code = 'DestReg = merge(SrcReg1, ProdLow, dataSize);' 550 551 class Muleh(RdRegOp): 552 def __init__(self, dest, src1=None, flags=None, dataSize="env.dataSize"): 553 if not src1: 554 src1 = dest 555 super(RdRegOp, self).__init__(dest, src1, "NUM_INTREGS", flags, dataSize) 556 code = 'DestReg = merge(SrcReg1, ProdHi, dataSize);' 557 flag_code = ''' 558 if (ProdHi) 559 ccFlagBits = ccFlagBits | (ext & (CFBit | OFBit | ECFBit)); 560 else 561 ccFlagBits = ccFlagBits & ~(ext & (CFBit | OFBit | ECFBit)); 562 ''' 563 564 # One or two bit divide 565 class Div1(WrRegOp): 566 code = ''' 567 //These are temporaries so that modifying them later won't make 568 //the ISA parser think they're also sources. 569 uint64_t quotient = 0; 570 uint64_t remainder = psrc1; 571 //Similarly, this is a temporary so changing it doesn't make it 572 //a source. 573 uint64_t divisor = op2; 574 //This is a temporary just for consistency and clarity. 575 uint64_t dividend = remainder; 576 //Do the division. 577 divide(dividend, divisor, quotient, remainder); 578 //Record the final results. 579 Remainder = remainder; 580 Quotient = quotient; 581 Divisor = divisor; 582 ''' 583 584 # Step divide 585 class Div2(RegOp): 586 code = ''' 587 uint64_t dividend = Remainder; 588 uint64_t divisor = Divisor; 589 uint64_t quotient = Quotient; 590 uint64_t remainder = dividend; 591 int remaining = op2; 592 //If we overshot, do nothing. This lets us unrool division loops a 593 //little. 594 if (remaining) { 595 //Shift in bits from the low order portion of the dividend 596 while(dividend < divisor && remaining) { 597 dividend = (dividend << 1) | bits(SrcReg1, remaining - 1); 598 quotient <<= 1; 599 remaining--; 600 } 601 remainder = dividend; 602 //Do the division. 603 divide(dividend, divisor, quotient, remainder); 604 } 605 //Keep track of how many bits there are still to pull in. 606 DestReg = merge(DestReg, remaining, dataSize); 607 //Record the final results 608 Remainder = remainder; 609 Quotient = quotient; 610 ''' 611 flag_code = ''' 612 if (DestReg == 0) 613 ccFlagBits = ccFlagBits | (ext & EZFBit); 614 else 615 ccFlagBits = ccFlagBits & ~(ext & EZFBit); 616 ''' 617 618 class Divq(RdRegOp): 619 code = 'DestReg = merge(SrcReg1, Quotient, dataSize);' 620 621 class Divr(RdRegOp): 622 code = 'DestReg = merge(SrcReg1, Remainder, dataSize);' 623 624 class Mov(CondRegOp): 625 code = 'DestReg = merge(SrcReg1, op2, dataSize)' 626 else_code = 'DestReg=DestReg;' 627 628 # Shift instructions 629 630 class Sll(RegOp): 631 code = ''' 632 uint8_t shiftAmt = (op2 & ((dataSize == 8) ? mask(6) : mask(5))); 633 DestReg = merge(DestReg, psrc1 << shiftAmt, dataSize); 634 ''' 635 flag_code = ''' 636 // If the shift amount is zero, no flags should be modified. 637 if (shiftAmt) { 638 //Zero out any flags we might modify. This way we only have to 639 //worry about setting them. 640 ccFlagBits = ccFlagBits & ~(ext & (CFBit | ECFBit | OFBit)); 641 int CFBits = 0; 642 //Figure out if we -would- set the CF bits if requested. 643 if (bits(SrcReg1, dataSize * 8 - shiftAmt)) 644 CFBits = 1; 645 //If some combination of the CF bits need to be set, set them. 646 if ((ext & (CFBit | ECFBit)) && CFBits) 647 ccFlagBits = ccFlagBits | (ext & (CFBit | ECFBit)); 648 //Figure out what the OF bit should be. 649 if ((ext & OFBit) && (CFBits ^ bits(DestReg, dataSize * 8 - 1))) 650 ccFlagBits = ccFlagBits | OFBit; 651 //Use the regular mechanisms to calculate the other flags. 652 ccFlagBits = genFlags(ccFlagBits, ext & ~(CFBit | ECFBit | OFBit), 653 DestReg, psrc1, op2); 654 } 655 ''' 656 657 class Srl(RegOp): 658 code = ''' 659 uint8_t shiftAmt = (op2 & ((dataSize == 8) ? mask(6) : mask(5))); 660 // Because what happens to the bits shift -in- on a right shift 661 // is not defined in the C/C++ standard, we have to mask them out 662 // to be sure they're zero. 663 uint64_t logicalMask = mask(dataSize * 8 - shiftAmt); 664 DestReg = merge(DestReg, (psrc1 >> shiftAmt) & logicalMask, dataSize); 665 ''' 666 flag_code = ''' 667 // If the shift amount is zero, no flags should be modified. 668 if (shiftAmt) { 669 //Zero out any flags we might modify. This way we only have to 670 //worry about setting them. 671 ccFlagBits = ccFlagBits & ~(ext & (CFBit | ECFBit | OFBit)); 672 //If some combination of the CF bits need to be set, set them. 673 if ((ext & (CFBit | ECFBit)) && bits(SrcReg1, shiftAmt - 1)) 674 ccFlagBits = ccFlagBits | (ext & (CFBit | ECFBit)); 675 //Figure out what the OF bit should be. 676 if ((ext & OFBit) && bits(SrcReg1, dataSize * 8 - 1)) 677 ccFlagBits = ccFlagBits | OFBit; 678 //Use the regular mechanisms to calculate the other flags. 679 ccFlagBits = genFlags(ccFlagBits, ext & ~(CFBit | ECFBit | OFBit), 680 DestReg, psrc1, op2); 681 } 682 ''' 683 684 class Sra(RegOp): 685 code = ''' 686 uint8_t shiftAmt = (op2 & ((dataSize == 8) ? mask(6) : mask(5))); 687 // Because what happens to the bits shift -in- on a right shift 688 // is not defined in the C/C++ standard, we have to sign extend 689 // them manually to be sure. 690 uint64_t arithMask = 691 -bits(psrc1, dataSize * 8 - 1) << (dataSize * 8 - shiftAmt); 692 DestReg = merge(DestReg, (psrc1 >> shiftAmt) | arithMask, dataSize); 693 ''' 694 flag_code = ''' 695 // If the shift amount is zero, no flags should be modified. 696 if (shiftAmt) { 697 //Zero out any flags we might modify. This way we only have to 698 //worry about setting them. 699 ccFlagBits = ccFlagBits & ~(ext & (CFBit | ECFBit | OFBit)); 700 //If some combination of the CF bits need to be set, set them. 701 if ((ext & (CFBit | ECFBit)) && bits(SrcReg1, shiftAmt - 1)) 702 ccFlagBits = ccFlagBits | (ext & (CFBit | ECFBit)); 703 //Use the regular mechanisms to calculate the other flags. 704 ccFlagBits = genFlags(ccFlagBits, ext & ~(CFBit | ECFBit | OFBit), 705 DestReg, psrc1, op2); 706 } 707 ''' 708 709 class Ror(RegOp): 710 code = ''' 711 uint8_t shiftAmt = 712 (op2 & ((dataSize == 8) ? mask(6) : mask(5))); 713 if(shiftAmt) 714 { 715 uint64_t top = psrc1 << (dataSize * 8 - shiftAmt); 716 uint64_t bottom = bits(psrc1, dataSize * 8, shiftAmt); 717 DestReg = merge(DestReg, top | bottom, dataSize); 718 } 719 else 720 DestReg = DestReg; 721 ''' 722 flag_code = ''' 723 // If the shift amount is zero, no flags should be modified. 724 if (shiftAmt) { 725 //Zero out any flags we might modify. This way we only have to 726 //worry about setting them. 727 ccFlagBits = ccFlagBits & ~(ext & (CFBit | ECFBit | OFBit)); 728 //Find the most and second most significant bits of the result. 729 int msb = bits(DestReg, dataSize * 8 - 1); 730 int smsb = bits(DestReg, dataSize * 8 - 2); 731 //If some combination of the CF bits need to be set, set them. 732 if ((ext & (CFBit | ECFBit)) && msb) 733 ccFlagBits = ccFlagBits | (ext & (CFBit | ECFBit)); 734 //Figure out what the OF bit should be. 735 if ((ext & OFBit) && (msb ^ smsb)) 736 ccFlagBits = ccFlagBits | OFBit; 737 //Use the regular mechanisms to calculate the other flags. 738 ccFlagBits = genFlags(ccFlagBits, ext & ~(CFBit | ECFBit | OFBit), 739 DestReg, psrc1, op2); 740 } 741 ''' 742 743 class Rcr(RegOp): 744 code = ''' 745 uint8_t shiftAmt = 746 (op2 & ((dataSize == 8) ? mask(6) : mask(5))); 747 if(shiftAmt) 748 { 749 CCFlagBits flags = ccFlagBits; 750 uint64_t top = flags.cf << (dataSize * 8 - shiftAmt); 751 if(shiftAmt > 1) 752 top |= psrc1 << (dataSize * 8 - shiftAmt - 1); 753 uint64_t bottom = bits(psrc1, dataSize * 8, shiftAmt); 754 DestReg = merge(DestReg, top | bottom, dataSize); 755 } 756 else 757 DestReg = DestReg; 758 ''' 759 flag_code = ''' 760 // If the shift amount is zero, no flags should be modified. 761 if (shiftAmt) { 762 //Zero out any flags we might modify. This way we only have to 763 //worry about setting them. 764 ccFlagBits = ccFlagBits & ~(ext & (CFBit | ECFBit | OFBit)); 765 //Figure out what the OF bit should be. 766 if ((ext & OFBit) && ((ccFlagBits & CFBit) ^ 767 bits(SrcReg1, dataSize * 8 - 1))) 768 ccFlagBits = ccFlagBits | OFBit; 769 //If some combination of the CF bits need to be set, set them. 770 if ((ext & (CFBit | ECFBit)) && bits(SrcReg1, shiftAmt - 1)) 771 ccFlagBits = ccFlagBits | (ext & (CFBit | ECFBit)); 772 //Use the regular mechanisms to calculate the other flags. 773 ccFlagBits = genFlags(ccFlagBits, ext & ~(CFBit | ECFBit | OFBit), 774 DestReg, psrc1, op2); 775 } 776 ''' 777 778 class Rol(RegOp): 779 code = ''' 780 uint8_t shiftAmt = 781 (op2 & ((dataSize == 8) ? mask(6) : mask(5))); 782 if(shiftAmt) 783 { 784 uint64_t top = psrc1 << shiftAmt; 785 uint64_t bottom = 786 bits(psrc1, dataSize * 8 - 1, dataSize * 8 - shiftAmt); 787 DestReg = merge(DestReg, top | bottom, dataSize); 788 } 789 else 790 DestReg = DestReg; 791 ''' 792 flag_code = ''' 793 // If the shift amount is zero, no flags should be modified. 794 if (shiftAmt) { 795 //Zero out any flags we might modify. This way we only have to 796 //worry about setting them. 797 ccFlagBits = ccFlagBits & ~(ext & (CFBit | ECFBit | OFBit)); 798 //The CF bits, if set, would be set to the lsb of the result. 799 int lsb = DestReg & 0x1; 800 int msb = bits(DestReg, dataSize * 8 - 1); 801 //If some combination of the CF bits need to be set, set them. 802 if ((ext & (CFBit | ECFBit)) && lsb) 803 ccFlagBits = ccFlagBits | (ext & (CFBit | ECFBit)); 804 //Figure out what the OF bit should be. 805 if ((ext & OFBit) && (msb ^ lsb)) 806 ccFlagBits = ccFlagBits | OFBit; 807 //Use the regular mechanisms to calculate the other flags. 808 ccFlagBits = genFlags(ccFlagBits, ext & ~(CFBit | ECFBit | OFBit), 809 DestReg, psrc1, op2); 810 } 811 ''' 812 813 class Rcl(RegOp): 814 code = ''' 815 uint8_t shiftAmt = 816 (op2 & ((dataSize == 8) ? mask(6) : mask(5))); 817 if(shiftAmt) 818 { 819 CCFlagBits flags = ccFlagBits; 820 uint64_t top = psrc1 << shiftAmt; 821 uint64_t bottom = flags.cf << (shiftAmt - 1); 822 if(shiftAmt > 1) 823 bottom |= 824 bits(psrc1, dataSize * 8 - 1, 825 dataSize * 8 - shiftAmt + 1); 826 DestReg = merge(DestReg, top | bottom, dataSize); 827 } 828 else 829 DestReg = DestReg; 830 ''' 831 flag_code = ''' 832 // If the shift amount is zero, no flags should be modified. 833 if (shiftAmt) { 834 //Zero out any flags we might modify. This way we only have to 835 //worry about setting them. 836 ccFlagBits = ccFlagBits & ~(ext & (CFBit | ECFBit | OFBit)); 837 int msb = bits(DestReg, dataSize * 8 - 1); 838 int CFBits = bits(SrcReg1, dataSize * 8 - shiftAmt); 839 //If some combination of the CF bits need to be set, set them. 840 if ((ext & (CFBit | ECFBit)) && CFBits) 841 ccFlagBits = ccFlagBits | (ext & (CFBit | ECFBit)); 842 //Figure out what the OF bit should be. 843 if ((ext & OFBit) && (msb ^ CFBits)) 844 ccFlagBits = ccFlagBits | OFBit; 845 //Use the regular mechanisms to calculate the other flags. 846 ccFlagBits = genFlags(ccFlagBits, ext & ~(CFBit | ECFBit | OFBit), 847 DestReg, psrc1, op2); 848 } 849 ''' 850 851 class Wrip(WrRegOp, CondRegOp): 852 code = 'RIP = psrc1 + sop2 + CSBase' 853 else_code="RIP = RIP;" 854 855 class Wruflags(WrRegOp): 856 code = 'ccFlagBits = psrc1 ^ op2' 857 858 class Wrflags(WrRegOp): 859 code = ''' 860 MiscReg newFlags = psrc1 ^ op2; 861 MiscReg userFlagMask = 0xDD5; 862 // Get only the user flags 863 ccFlagBits = newFlags & userFlagMask; 864 // Get everything else 865 nccFlagBits = newFlags & ~userFlagMask; 866 ''' 867 868 class Rdip(RdRegOp): 869 code = 'DestReg = RIP - CSBase' 870 871 class Ruflags(RdRegOp): 872 code = 'DestReg = ccFlagBits' 873 874 class Rflags(RdRegOp): 875 code = 'DestReg = ccFlagBits | nccFlagBits' 876 877 class Ruflag(RegOp): 878 code = ''' 879 int flag = bits(ccFlagBits, imm8); 880 DestReg = merge(DestReg, flag, dataSize); 881 ccFlagBits = (flag == 0) ? (ccFlagBits | EZFBit) : 882 (ccFlagBits & ~EZFBit); 883 ''' 884 def __init__(self, dest, imm, flags=None, \ 885 dataSize="env.dataSize"): 886 super(Ruflag, self).__init__(dest, \ 887 "NUM_INTREGS", imm, flags, dataSize) 888 889 class Rflag(RegOp): 890 code = ''' 891 MiscReg flagMask = 0x3F7FDD5; 892 MiscReg flags = (nccFlagBits | ccFlagBits) & flagMask; 893 int flag = bits(flags, imm8); 894 DestReg = merge(DestReg, flag, dataSize); 895 ccFlagBits = (flag == 0) ? (ccFlagBits | EZFBit) : 896 (ccFlagBits & ~EZFBit); 897 ''' 898 def __init__(self, dest, imm, flags=None, \ 899 dataSize="env.dataSize"): 900 super(Rflag, self).__init__(dest, \ 901 "NUM_INTREGS", imm, flags, dataSize) 902 903 class Sext(RegOp): 904 code = ''' 905 IntReg val = psrc1; 906 // Mask the bit position so that it wraps. 907 int bitPos = op2 & (dataSize * 8 - 1); 908 int sign_bit = bits(val, bitPos, bitPos); 909 uint64_t maskVal = mask(bitPos+1); 910 val = sign_bit ? (val | ~maskVal) : (val & maskVal); 911 DestReg = merge(DestReg, val, dataSize); 912 ''' 913 flag_code = ''' 914 if (!sign_bit) 915 ccFlagBits = ccFlagBits & 916 ~(ext & (CFBit | ECFBit | ZFBit | EZFBit)); 917 else 918 ccFlagBits = ccFlagBits | 919 (ext & (CFBit | ECFBit | ZFBit | EZFBit)); 920 ''' 921 922 class Zext(RegOp): 923 code = 'DestReg = bits(psrc1, op2, 0);' 924 925 class Rdcr(RegOp): 926 def __init__(self, dest, src1, flags=None, dataSize="env.dataSize"): 927 super(Rdcr, self).__init__(dest, \ 928 src1, "NUM_INTREGS", flags, dataSize) 929 code = ''' 930 if (dest == 1 || (dest > 4 && dest < 8) || (dest > 8)) { 931 fault = new InvalidOpcode(); 932 } else { 933 DestReg = ControlSrc1; 934 } 935 ''' 936 937 class Wrcr(RegOp): 938 def __init__(self, dest, src1, flags=None, dataSize="env.dataSize"): 939 super(Wrcr, self).__init__(dest, \ 940 src1, "NUM_INTREGS", flags, dataSize) 941 code = ''' 942 if (dest == 1 || (dest > 4 && dest < 8) || (dest > 8)) { 943 fault = new InvalidOpcode(); 944 } else { 945 // There are *s in the line below so it doesn't confuse the 946 // parser. They may be unnecessary. 947 //Mis*cReg old*Val = pick(Cont*rolDest, 0, dat*aSize); 948 MiscReg newVal = psrc1; 949 950 // Check for any modifications that would cause a fault. 951 switch(dest) { 952 case 0: 953 { 954 Efer efer = EferOp; 955 CR0 cr0 = newVal; 956 CR4 oldCr4 = CR4Op; 957 if (bits(newVal, 63, 32) || 958 (!cr0.pe && cr0.pg) || 959 (!cr0.cd && cr0.nw) || 960 (cr0.pg && efer.lme && !oldCr4.pae)) 961 fault = new GeneralProtection(0); 962 } 963 break; 964 case 2: 965 break; 966 case 3: 967 break; 968 case 4: 969 { 970 CR4 cr4 = newVal; 971 // PAE can't be disabled in long mode. 972 if (bits(newVal, 63, 11) || 973 (machInst.mode.mode == LongMode && !cr4.pae)) 974 fault = new GeneralProtection(0); 975 } 976 break; 977 case 8: 978 { 979 if (bits(newVal, 63, 4)) 980 fault = new GeneralProtection(0); 981 } 982 default: 983 panic("Unrecognized control register %d.\\n", dest); 984 } 985 ControlDest = newVal; 986 } 987 ''' 988 989 # Microops for manipulating segmentation registers 990 class SegOp(CondRegOp): 991 abstract = True 992 def __init__(self, dest, src1, flags=None, dataSize="env.dataSize"): 993 super(SegOp, self).__init__(dest, \ 994 src1, "NUM_INTREGS", flags, dataSize) 995 996 class Wrbase(SegOp): 997 code = ''' 998 SegBaseDest = psrc1; 999 ''' 1000 1001 class Wrlimit(SegOp): 1002 code = ''' 1003 SegLimitDest = psrc1; 1004 ''' 1005 1006 class Wrsel(SegOp): 1007 code = ''' 1008 SegSelDest = psrc1; 1009 ''' 1010 1011 class Rdbase(SegOp): 1012 code = ''' 1013 DestReg = SegBaseSrc1; 1014 ''' 1015 1016 class Rdlimit(SegOp): 1017 code = ''' 1018 DestReg = SegLimitSrc1; 1019 ''' 1020 1021 class RdAttr(SegOp): 1022 code = ''' 1023 DestReg = SegAttrSrc1; 1024 ''' 1025 1026 class Rdsel(SegOp): 1027 code = ''' 1028 DestReg = SegSelSrc1; 1029 ''' 1030 1031 class Rdval(RegOp): 1032 def __init__(self, dest, src1, flags=None, dataSize="env.dataSize"): 1033 super(Rdval, self).__init__(dest, \ 1034 src1, "NUM_INTREGS", flags, dataSize) 1035 code = ''' 1036 DestReg = MiscRegSrc1; 1037 ''' 1038 1039 class Wrval(RegOp): 1040 def __init__(self, dest, src1, flags=None, dataSize="env.dataSize"): 1041 super(Wrval, self).__init__(dest, \ 1042 src1, "NUM_INTREGS", flags, dataSize) 1043 code = ''' 1044 MiscRegDest = SrcReg1; 1045 ''' 1046 1047 class Chks(RegOp): 1048 def __init__(self, dest, src1, src2=0, 1049 flags=None, dataSize="env.dataSize"): 1050 super(Chks, self).__init__(dest, 1051 src1, src2, flags, dataSize) 1052 code = ''' 1053 // The selector is in source 1 and can be at most 16 bits. 1054 SegSelector selector = DestReg; 1055 SegDescriptor desc = SrcReg1; 1056 HandyM5Reg m5reg = M5Reg; 1057 1058 switch (imm8) 1059 { 1060 case SegNoCheck: 1061 break; 1062 case SegCSCheck: 1063 panic("CS checks for far calls/jumps not implemented.\\n"); 1064 break; 1065 case SegCallGateCheck: 1066 panic("CS checks for far calls/jumps through call gates" 1067 "not implemented.\\n"); 1068 break; 1069 case SegIntGateCheck: 1070 if (desc.dpl < m5reg.cpl) { 1071 fault = new GeneralProtection((uint16_t)selector); 1072 } 1073 break; 1074 case SegSSCheck: 1075 if (selector.si || selector.ti) { 1076 if (!desc.p) { 1077 //FIXME This needs to also push the selector. 1078 fault = new StackFault; 1079 } 1080 } else { 1081 if ((m5reg.submode != SixtyFourBitMode || 1082 m5reg.cpl == 3) || 1083 !(desc.s == 1 && 1084 desc.type.codeOrData == 0 && desc.type.w) || 1085 (desc.dpl != m5reg.cpl) || 1086 (selector.rpl != m5reg.cpl)) { 1087 fault = new GeneralProtection(psrc1 & 0xFFFF); 1088 } 1089 } 1090 break; 1091 case SegIretCheck: 1092 { 1093 if ((!selector.si && !selector.ti) || 1094 (selector.rpl < m5reg.cpl) || 1095 !(desc.s == 1 && desc.type.codeOrData == 1) || 1096 (!desc.type.c && desc.dpl != selector.rpl) || 1097 (desc.type.c && desc.dpl > selector.rpl)) { 1098 fault = new GeneralProtection(psrc1 & 0xFFFF); 1099 } else if (!desc.p) { 1100 fault = new SegmentNotPresent; 1101 } 1102 break; 1103 } 1104 case SegIntCSCheck: 1105 if (m5reg.mode == LongMode) { 1106 if (desc.l != 1 || desc.d != 0) { 1107 fault = new GeneralProtection(selector); 1108 } 1109 } else { 1110 panic("Interrupt CS checks not implemented " 1111 "in legacy mode.\\n"); 1112 } 1113 break; 1114 default: 1115 panic("Undefined segment check type.\\n"); 1116 } 1117 ''' 1118 flag_code = ''' 1119 // Check for a NULL selector and set ZF,EZF appropriately. 1120 ccFlagBits = ccFlagBits & ~(ext & (ZFBit | EZFBit)); 1121 if (!selector.si && !selector.ti) 1122 ccFlagBits = ccFlagBits | (ext & (ZFBit | EZFBit)); 1123 ''' 1124 1125 class Wrdh(RegOp): 1126 code = ''' 1127 SegDescriptor desc = SrcReg1; 1128 1129 uint64_t target = bits(SrcReg2, 31, 0) << 32; 1130 switch(desc.type) { 1131 case LDT64: 1132 case AvailableTSS64: 1133 case BusyTSS64: 1134 replaceBits(target, 23, 0, desc.baseLow); 1135 replaceBits(target, 31, 24, desc.baseHigh); 1136 break; 1137 case CallGate64: 1138 case IntGate64: 1139 case TrapGate64: 1140 replaceBits(target, 15, 0, bits(desc, 15, 0)); 1141 replaceBits(target, 31, 16, bits(desc, 63, 48)); 1142 break; 1143 default: 1144 panic("Wrdh used with wrong descriptor type!\\n"); 1145 } 1146 DestReg = target; 1147 ''' 1148 1149 class Wrtsc(WrRegOp): 1150 code = ''' 1151 TscOp = psrc1; 1152 ''' 1153 1154 class Rdtsc(RdRegOp): 1155 code = ''' 1156 DestReg = TscOp; 1157 ''' 1158 1159 class Rdm5reg(RdRegOp): 1160 code = ''' 1161 DestReg = M5Reg; 1162 ''' 1163 1164 class Wrdl(RegOp): 1165 code = ''' 1166 SegDescriptor desc = SrcReg1; 1167 SegSelector selector = SrcReg2; 1168 if (selector.si || selector.ti) { 1169 SegAttr attr = 0; 1170 attr.dpl = desc.dpl; 1171 attr.defaultSize = desc.d; 1172 if (!desc.s) { 1173 SegBaseDest = SegBaseDest; 1174 SegLimitDest = SegLimitDest; 1175 SegAttrDest = SegAttrDest; 1176 panic("System segment encountered.\\n"); 1177 } else { 1178 if (!desc.p) 1179 panic("Segment not present.\\n"); 1180 if (desc.type.codeOrData) { 1181 attr.readable = desc.type.r; 1182 attr.longMode = desc.l; 1183 } else { 1184 attr.expandDown = desc.type.e; 1185 attr.readable = 1; 1186 attr.writable = desc.type.w; 1187 } 1188 Addr base = desc.baseLow | (desc.baseHigh << 24); 1189 Addr limit = desc.limitLow | (desc.limitHigh << 16); 1190 if (desc.g) 1191 limit = (limit << 12) | mask(12); 1192 SegBaseDest = base; 1193 SegLimitDest = limit; 1194 SegAttrDest = attr; 1195 } 1196 } else { 1197 SegBaseDest = SegBaseDest; 1198 SegLimitDest = SegLimitDest; 1199 SegAttrDest = SegAttrDest; 1200 } 1201 ''' 1202}}; 1203