3// All rights reserved. 4// 5// The license below extends only to copyright in the software and shall 6// not be construed as granting a license to any other intellectual 7// property including but not limited to intellectual property relating 8// to a hardware implementation of the functionality of the software 9// licensed hereunder. You may use the software subject to the license 10// terms below provided that you ensure that this notice is replicated 11// unmodified and in its entirety in all distributions of the software, 12// modified or unmodified, in source code or in binary form. 13// 14// Redistribution and use in source and binary forms, with or without 15// modification, are permitted provided that the following conditions are 16// met: redistributions of source code must retain the above copyright 17// notice, this list of conditions and the following disclaimer; 18// redistributions in binary form must reproduce the above copyright 19// notice, this list of conditions and the following disclaimer in the 20// documentation and/or other materials provided with the distribution; 21// neither the name of the copyright holders nor the names of its 22// contributors may be used to endorse or promote products derived from 23// this software without specific prior written permission. 24// 25// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36// 37// Authors: Gabe Black 38// Nilay Vaish 39 40////////////////////////////////////////////////////////////////////////// 41// 42// FpOp Microop templates 43// 44////////////////////////////////////////////////////////////////////////// 45 46def template MicroFpOpExecute {{ 47 Fault %(class_name)s::execute(CPU_EXEC_CONTEXT *xc, 48 Trace::InstRecord *traceData) const 49 { 50 Fault fault = NoFault; 51 52 DPRINTF(X86, "The data size is %d\n", dataSize); 53 %(op_decl)s; 54 %(op_rd)s; 55 56 if(%(cond_check)s) 57 { 58 %(code)s; 59 %(flag_code)s; 60 %(tag_code)s; 61 %(top_code)s; 62 } 63 else 64 { 65 %(else_code)s; 66 } 67 68 //Write the resulting state to the execution context 69 if(fault == NoFault) 70 { 71 %(op_wb)s; 72 } 73 return fault; 74 } 75}}; 76 77def template MicroFpOpDeclare {{ 78 class %(class_name)s : public %(base_class)s 79 { 80 public: 81 %(class_name)s(ExtMachInst _machInst, 82 const char * instMnem, uint64_t setFlags, 83 InstRegIndex _src1, InstRegIndex _src2, InstRegIndex _dest, 84 uint8_t _dataSize, int8_t _spm); 85 86 %(BasicExecDeclare)s 87 }; 88}}; 89 90def template MicroFpOpConstructor {{ 91 %(class_name)s::%(class_name)s( 92 ExtMachInst machInst, const char * instMnem, uint64_t setFlags, 93 InstRegIndex _src1, InstRegIndex _src2, InstRegIndex _dest, 94 uint8_t _dataSize, int8_t _spm) : 95 %(base_class)s(machInst, "%(mnemonic)s", instMnem, setFlags, 96 _src1, _src2, _dest, _dataSize, _spm, 97 %(op_class)s) 98 { 99 %(constructor)s; 100 } 101}}; 102 103let {{ 104 # Make these empty strings so that concatenating onto 105 # them will always work. 106 header_output = "" 107 decoder_output = "" 108 exec_output = "" 109 110 class FpOpMeta(type): 111 def buildCppClasses(self, name, Name, suffix, \ 112 code, flag_code, cond_check, else_code, op_class): 113 114 # Globals to stick the output in 115 global header_output 116 global decoder_output 117 global exec_output 118 119 # Stick all the code together so it can be searched at once 120 allCode = "|".join((code, flag_code, cond_check, else_code)) 121 122 # If there's something optional to do with flags, generate 123 # a version without it and fix up this version to use it. 124 if flag_code is not "" or cond_check is not "true": 125 self.buildCppClasses(name, Name, suffix, 126 code, "", "true", else_code, op_class) 127 suffix = "Flags" + suffix 128 129 base = "X86ISA::FpOp" 130 131 # Get everything ready for the substitution 132 iop_tag = InstObjParams(name, Name + suffix + "TopTag", base, 133 {"code" : code, 134 "flag_code" : flag_code, 135 "cond_check" : cond_check, 136 "else_code" : else_code, 137 "tag_code" : "FTW = genX87Tags(FTW, TOP, spm);", 138 "top_code" : "TOP = (TOP + spm + 8) % 8;", 139 "op_class" : op_class}) 140 iop_top = InstObjParams(name, Name + suffix + "Top", base, 141 {"code" : code, 142 "flag_code" : flag_code, 143 "cond_check" : cond_check, 144 "else_code" : else_code, 145 "tag_code" : ";", 146 "top_code" : "TOP = (TOP + spm + 8) % 8;", 147 "op_class" : op_class}) 148 iop = InstObjParams(name, Name + suffix, base, 149 {"code" : code, 150 "flag_code" : flag_code, 151 "cond_check" : cond_check, 152 "else_code" : else_code, 153 "tag_code" : ";", 154 "top_code" : ";", 155 "op_class" : op_class}) 156 157 # Generate the actual code (finally!) 158 header_output += MicroFpOpDeclare.subst(iop_tag) 159 decoder_output += MicroFpOpConstructor.subst(iop_tag) 160 exec_output += MicroFpOpExecute.subst(iop_tag) 161 header_output += MicroFpOpDeclare.subst(iop_top) 162 decoder_output += MicroFpOpConstructor.subst(iop_top) 163 exec_output += MicroFpOpExecute.subst(iop_top) 164 header_output += MicroFpOpDeclare.subst(iop) 165 decoder_output += MicroFpOpConstructor.subst(iop) 166 exec_output += MicroFpOpExecute.subst(iop) 167 168 169 def __new__(mcls, Name, bases, dict): 170 abstract = False 171 name = Name.lower() 172 if "abstract" in dict: 173 abstract = dict['abstract'] 174 del dict['abstract'] 175 176 cls = super(FpOpMeta, mcls).__new__(mcls, Name, bases, dict) 177 if not abstract: 178 cls.className = Name 179 cls.mnemonic = name 180 code = cls.code 181 flag_code = cls.flag_code 182 cond_check = cls.cond_check 183 else_code = cls.else_code 184 op_class = cls.op_class 185 186 # Set up the C++ classes 187 mcls.buildCppClasses(cls, name, Name, "", 188 code, flag_code, cond_check, else_code, op_class) 189 190 # Hook into the microassembler dict 191 global microopClasses 192 microopClasses[name] = cls 193 194 return cls 195 196 class FpUnaryOp(X86Microop): 197 __metaclass__ = FpOpMeta 198 # This class itself doesn't act as a microop 199 abstract = True 200 201 # Default template parameter values 202 flag_code = "" 203 cond_check = "true" 204 else_code = ";" 205 op_class = "FloatAddOp" 206 207 def __init__(self, dest, src1, spm=0, \ 208 SetStatus=False, UpdateFTW=True, dataSize="env.dataSize"): 209 self.dest = dest 210 self.src1 = src1 211 self.src2 = "InstRegIndex(0)" 212 self.spm = spm 213 self.dataSize = dataSize 214 if SetStatus: 215 self.className += "Flags" 216 if spm: 217 self.className += "Top" 218 if spm and UpdateFTW: 219 self.className += "Tag" 220 221 def getAllocator(self, microFlags): 222 return '''new %(class_name)s(machInst, macrocodeBlock, 223 %(flags)s, %(src1)s, %(src2)s, %(dest)s, 224 %(dataSize)s, %(spm)d)''' % { 225 "class_name" : self.className, 226 "flags" : self.microFlagsText(microFlags), 227 "src1" : self.src1, "src2" : self.src2, 228 "dest" : self.dest, 229 "dataSize" : self.dataSize, 230 "spm" : self.spm} 231 232 class FpBinaryOp(X86Microop): 233 __metaclass__ = FpOpMeta 234 # This class itself doesn't act as a microop 235 abstract = True 236 237 # Default template parameter values 238 flag_code = "" 239 cond_check = "true" 240 else_code = ";" 241 op_class = "FloatAddOp" 242 243 def __init__(self, dest, src1, src2, spm=0, \ 244 SetStatus=False, UpdateFTW=True, dataSize="env.dataSize"): 245 self.dest = dest 246 self.src1 = src1 247 self.src2 = src2 248 self.spm = spm 249 self.dataSize = dataSize 250 if SetStatus: 251 self.className += "Flags" 252 if spm: 253 self.className += "Top" 254 if spm and UpdateFTW: 255 self.className += "Tag" 256 257 def getAllocator(self, microFlags): 258 return '''new %(class_name)s(machInst, macrocodeBlock, 259 %(flags)s, %(src1)s, %(src2)s, %(dest)s, 260 %(dataSize)s, %(spm)d)''' % { 261 "class_name" : self.className, 262 "flags" : self.microFlagsText(microFlags), 263 "src1" : self.src1, "src2" : self.src2, 264 "dest" : self.dest, 265 "dataSize" : self.dataSize, 266 "spm" : self.spm} 267 268 class Movfp(FpUnaryOp): 269 code = 'FpDestReg_uqw = FpSrcReg1_uqw;' 270 else_code = 'FpDestReg_uqw = FpDestReg_uqw;' 271 cond_check = "checkCondition(ccFlagBits | cfofBits | dfBit | \ 272 ecfBit | ezfBit, src2)" 273 op_class = 'IntAluOp' 274 275 class Xorfp(FpBinaryOp): 276 code = 'FpDestReg_uqw = FpSrcReg1_uqw ^ FpSrcReg2_uqw;' 277 278 class Sqrtfp(FpBinaryOp): 279 code = 'FpDestReg = sqrt(FpSrcReg2);' 280 op_class = 'FloatSqrtOp' 281 282 class Cosfp(FpUnaryOp): 283 code = 'FpDestReg = cos(FpSrcReg1);' 284 op_class = 'FloatSqrtOp' 285 286 class Sinfp(FpUnaryOp): 287 code = 'FpDestReg = sin(FpSrcReg1);' 288 op_class = 'FloatSqrtOp' 289 290 class Tanfp(FpUnaryOp): 291 code = 'FpDestReg = tan(FpSrcReg1);' 292 op_class = 'FloatSqrtOp' 293 294 295 # Conversion microops 296 class ConvOp(FpBinaryOp): 297 abstract = True 298 op_class = 'FloatCvtOp' 299 def __init__(self, dest, src1, **kwargs): 300 super(ConvOp, self).__init__(dest, src1, \ 301 "InstRegIndex(FLOATREG_MICROFP0)", \ 302 **kwargs) 303 304 # These probably shouldn't look at the ExtMachInst directly to figure 305 # out what size to use and should instead delegate that to the macroop's 306 # constructor. That would be more efficient, and it would make the 307 # microops a little more modular. 308 class cvtf_i2d(ConvOp): 309 code = ''' 310 X86IntReg intReg = SSrcReg1; 311 if (REX_W) 312 FpDestReg = intReg.SR; 313 else 314 FpDestReg = intReg.SE; 315 ''' 316 317 class cvtf_i2d_hi(ConvOp): 318 code = 'FpDestReg = bits(SSrcReg1, 63, 32);' 319 320 class cvtf_d2i(ConvOp): 321 code = ''' 322 int64_t intSrcReg1 = static_cast<int64_t>(FpSrcReg1); 323 if (REX_W) 324 SDestReg = intSrcReg1; 325 else 326 SDestReg = merge(SDestReg, intSrcReg1, 4); 327 ''' 328 329 # Convert two integers registers representing an 80-bit floating 330 # point number to an x87 register. 331 class cvtint_fp80(FpBinaryOp): 332 code = ''' 333 uint8_t bits[10]; 334 *(uint64_t *)(bits + 0) = SSrcReg1; 335 *(uint16_t *)(bits + 8) = (uint16_t)SSrcReg2; 336 FpDestReg = loadFloat80(bits); 337 ''' 338 339 # Convert an x87 register (double) into extended precision and 340 # extract the highest 64 bits. 341 class cvtfp80h_int(ConvOp): 342 code = ''' 343 char bits[10]; 344 storeFloat80(bits, FpSrcReg1); 345 SDestReg = *(uint64_t *)(bits + 0); 346 ''' 347 348 # Convert an x87 register (double) into extended precision and 349 # extract the lowest 16 bits. 350 class cvtfp80l_int(ConvOp): 351 code = ''' 352 char bits[10]; 353 storeFloat80(bits, FpSrcReg1); 354 SDestReg = *(uint16_t *)(bits + 8); 355 ''' 356 357 # These need to consider size at some point. They'll always use doubles 358 # for the moment. 359 class addfp(FpBinaryOp): 360 code = 'FpDestReg = FpSrcReg1 + FpSrcReg2;' 361 362 class mulfp(FpBinaryOp): 363 code = 'FpDestReg = FpSrcReg1 * FpSrcReg2;' 364 op_class = 'FloatMultOp' 365 366 class divfp(FpBinaryOp): 367 code = 'FpDestReg = FpSrcReg1 / FpSrcReg2;' 368 op_class = 'FloatDivOp' 369 370 class subfp(FpBinaryOp): 371 code = 'FpDestReg = FpSrcReg1 - FpSrcReg2;' 372 373 class Yl2xFp(FpBinaryOp): 374 code = ''' 375 FpDestReg = FpSrcReg2 * (log(FpSrcReg1) / log(2)); 376 ''' 377 op_class = 'FloatSqrtOp' 378 379 class PremFp(FpBinaryOp): 380 code = ''' 381 MiscReg new_fsw(FSW); 382 int src1_exp; 383 int src2_exp; 384 std::frexp(FpSrcReg1, &src1_exp); 385 std::frexp(FpSrcReg2, &src2_exp); 386 387 const int d(src2_exp - src1_exp); 388 if (d < 64) { 389 const int64_t q(std::trunc(FpSrcReg2 / FpSrcReg1)); 390 FpDestReg = FpSrcReg2 - FpSrcReg1 * q; 391 new_fsw &= ~(CC0Bit | CC1Bit | CC2Bit | CC2Bit); 392 new_fsw |= (q & 0x1) ? CC1Bit : 0; 393 new_fsw |= (q & 0x2) ? CC3Bit : 0; 394 new_fsw |= (q & 0x4) ? CC0Bit : 0; 395 } else { 396 const int n(42); 397 const int64_t qq(std::trunc( 398 FpSrcReg2 / std::ldexp(FpSrcReg1, d - n))); 399 FpDestReg = FpSrcReg2 - std::ldexp(FpSrcReg1 * qq, d - n); 400 new_fsw |= CC2Bit; 401 } 402 DPRINTF(X86, "src1: %lf, src2: %lf, dest: %lf, FSW: 0x%x\\n", 403 FpSrcReg1, FpSrcReg2, FpDestReg, new_fsw); 404 ''' 405 op_class = 'FloatDivOp' 406 407 flag_code = 'FSW = new_fsw;' 408 409 class Compfp(FpBinaryOp): 410 def __init__(self, src1, src2, spm=0, setStatus=False, updateFTW=True, \ 411 dataSize="env.dataSize"): 412 super(Compfp, self).__init__("InstRegIndex(FLOATREG_MICROFP0)", \ 413 src1, src2, spm, setStatus, updateFTW, dataSize) 414 # This class sets the condition codes in rflags according to the 415 # rules for comparing floating point. 416 code = ''' 417 // ZF PF CF 418 // Unordered 1 1 1 419 // Greater than 0 0 0 420 // Less than 0 0 1 421 // Equal 1 0 0 422 // OF = SF = AF = 0 423 ccFlagBits = ccFlagBits & ~(SFBit | AFBit | ZFBit | PFBit); 424 cfofBits = cfofBits & ~(OFBit | CFBit); 425 426 if (std::isnan(FpSrcReg1) || std::isnan(FpSrcReg2)) { 427 ccFlagBits = ccFlagBits | (ZFBit | PFBit); 428 cfofBits = cfofBits | CFBit; 429 } 430 else if(FpSrcReg1 < FpSrcReg2) 431 cfofBits = cfofBits | CFBit; 432 else if(FpSrcReg1 == FpSrcReg2) 433 ccFlagBits = ccFlagBits | ZFBit; 434 ''' 435 op_class = 'FloatCmpOp' 436 437 class absfp(FpUnaryOp): 438 code = 'FpDestReg = fabs(FpSrcReg1);' 439 flag_code = 'FSW = FSW & (~CC1Bit);' 440 441 class chsfp(FpUnaryOp): 442 code = 'FpDestReg = (-1) * (FpSrcReg1);' 443 flag_code = 'FSW = FSW & (~CC1Bit);' 444 445 class Pop87(FpUnaryOp): 446 def __init__(self, spm=1, UpdateFTW=True): 447 super(Pop87, self).__init__( \ 448 "InstRegIndex(FLOATREG_MICROFP0)", \ 449 "InstRegIndex(FLOATREG_MICROFP0)", \ 450 spm=spm, SetStatus=False, UpdateFTW=UpdateFTW) 451 452 code = '' 453 op_class = 'IntAluOp' 454}};
| 5// All rights reserved. 6// 7// The license below extends only to copyright in the software and shall 8// not be construed as granting a license to any other intellectual 9// property including but not limited to intellectual property relating 10// to a hardware implementation of the functionality of the software 11// licensed hereunder. You may use the software subject to the license 12// terms below provided that you ensure that this notice is replicated 13// unmodified and in its entirety in all distributions of the software, 14// modified or unmodified, in source code or in binary form. 15// 16// Redistribution and use in source and binary forms, with or without 17// modification, are permitted provided that the following conditions are 18// met: redistributions of source code must retain the above copyright 19// notice, this list of conditions and the following disclaimer; 20// redistributions in binary form must reproduce the above copyright 21// notice, this list of conditions and the following disclaimer in the 22// documentation and/or other materials provided with the distribution; 23// neither the name of the copyright holders nor the names of its 24// contributors may be used to endorse or promote products derived from 25// this software without specific prior written permission. 26// 27// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 28// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 29// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 30// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 31// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 32// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 33// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 34// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 35// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 36// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 37// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 38// 39// Authors: Gabe Black 40// Nilay Vaish 41 42////////////////////////////////////////////////////////////////////////// 43// 44// FpOp Microop templates 45// 46////////////////////////////////////////////////////////////////////////// 47 48def template MicroFpOpExecute {{ 49 Fault %(class_name)s::execute(CPU_EXEC_CONTEXT *xc, 50 Trace::InstRecord *traceData) const 51 { 52 Fault fault = NoFault; 53 54 DPRINTF(X86, "The data size is %d\n", dataSize); 55 %(op_decl)s; 56 %(op_rd)s; 57 58 if(%(cond_check)s) 59 { 60 %(code)s; 61 %(flag_code)s; 62 %(tag_code)s; 63 %(top_code)s; 64 } 65 else 66 { 67 %(else_code)s; 68 } 69 70 //Write the resulting state to the execution context 71 if(fault == NoFault) 72 { 73 %(op_wb)s; 74 } 75 return fault; 76 } 77}}; 78 79def template MicroFpOpDeclare {{ 80 class %(class_name)s : public %(base_class)s 81 { 82 public: 83 %(class_name)s(ExtMachInst _machInst, 84 const char * instMnem, uint64_t setFlags, 85 InstRegIndex _src1, InstRegIndex _src2, InstRegIndex _dest, 86 uint8_t _dataSize, int8_t _spm); 87 88 %(BasicExecDeclare)s 89 }; 90}}; 91 92def template MicroFpOpConstructor {{ 93 %(class_name)s::%(class_name)s( 94 ExtMachInst machInst, const char * instMnem, uint64_t setFlags, 95 InstRegIndex _src1, InstRegIndex _src2, InstRegIndex _dest, 96 uint8_t _dataSize, int8_t _spm) : 97 %(base_class)s(machInst, "%(mnemonic)s", instMnem, setFlags, 98 _src1, _src2, _dest, _dataSize, _spm, 99 %(op_class)s) 100 { 101 %(constructor)s; 102 } 103}}; 104 105let {{ 106 # Make these empty strings so that concatenating onto 107 # them will always work. 108 header_output = "" 109 decoder_output = "" 110 exec_output = "" 111 112 class FpOpMeta(type): 113 def buildCppClasses(self, name, Name, suffix, \ 114 code, flag_code, cond_check, else_code, op_class): 115 116 # Globals to stick the output in 117 global header_output 118 global decoder_output 119 global exec_output 120 121 # Stick all the code together so it can be searched at once 122 allCode = "|".join((code, flag_code, cond_check, else_code)) 123 124 # If there's something optional to do with flags, generate 125 # a version without it and fix up this version to use it. 126 if flag_code is not "" or cond_check is not "true": 127 self.buildCppClasses(name, Name, suffix, 128 code, "", "true", else_code, op_class) 129 suffix = "Flags" + suffix 130 131 base = "X86ISA::FpOp" 132 133 # Get everything ready for the substitution 134 iop_tag = InstObjParams(name, Name + suffix + "TopTag", base, 135 {"code" : code, 136 "flag_code" : flag_code, 137 "cond_check" : cond_check, 138 "else_code" : else_code, 139 "tag_code" : "FTW = genX87Tags(FTW, TOP, spm);", 140 "top_code" : "TOP = (TOP + spm + 8) % 8;", 141 "op_class" : op_class}) 142 iop_top = InstObjParams(name, Name + suffix + "Top", base, 143 {"code" : code, 144 "flag_code" : flag_code, 145 "cond_check" : cond_check, 146 "else_code" : else_code, 147 "tag_code" : ";", 148 "top_code" : "TOP = (TOP + spm + 8) % 8;", 149 "op_class" : op_class}) 150 iop = InstObjParams(name, Name + suffix, base, 151 {"code" : code, 152 "flag_code" : flag_code, 153 "cond_check" : cond_check, 154 "else_code" : else_code, 155 "tag_code" : ";", 156 "top_code" : ";", 157 "op_class" : op_class}) 158 159 # Generate the actual code (finally!) 160 header_output += MicroFpOpDeclare.subst(iop_tag) 161 decoder_output += MicroFpOpConstructor.subst(iop_tag) 162 exec_output += MicroFpOpExecute.subst(iop_tag) 163 header_output += MicroFpOpDeclare.subst(iop_top) 164 decoder_output += MicroFpOpConstructor.subst(iop_top) 165 exec_output += MicroFpOpExecute.subst(iop_top) 166 header_output += MicroFpOpDeclare.subst(iop) 167 decoder_output += MicroFpOpConstructor.subst(iop) 168 exec_output += MicroFpOpExecute.subst(iop) 169 170 171 def __new__(mcls, Name, bases, dict): 172 abstract = False 173 name = Name.lower() 174 if "abstract" in dict: 175 abstract = dict['abstract'] 176 del dict['abstract'] 177 178 cls = super(FpOpMeta, mcls).__new__(mcls, Name, bases, dict) 179 if not abstract: 180 cls.className = Name 181 cls.mnemonic = name 182 code = cls.code 183 flag_code = cls.flag_code 184 cond_check = cls.cond_check 185 else_code = cls.else_code 186 op_class = cls.op_class 187 188 # Set up the C++ classes 189 mcls.buildCppClasses(cls, name, Name, "", 190 code, flag_code, cond_check, else_code, op_class) 191 192 # Hook into the microassembler dict 193 global microopClasses 194 microopClasses[name] = cls 195 196 return cls 197 198 class FpUnaryOp(X86Microop): 199 __metaclass__ = FpOpMeta 200 # This class itself doesn't act as a microop 201 abstract = True 202 203 # Default template parameter values 204 flag_code = "" 205 cond_check = "true" 206 else_code = ";" 207 op_class = "FloatAddOp" 208 209 def __init__(self, dest, src1, spm=0, \ 210 SetStatus=False, UpdateFTW=True, dataSize="env.dataSize"): 211 self.dest = dest 212 self.src1 = src1 213 self.src2 = "InstRegIndex(0)" 214 self.spm = spm 215 self.dataSize = dataSize 216 if SetStatus: 217 self.className += "Flags" 218 if spm: 219 self.className += "Top" 220 if spm and UpdateFTW: 221 self.className += "Tag" 222 223 def getAllocator(self, microFlags): 224 return '''new %(class_name)s(machInst, macrocodeBlock, 225 %(flags)s, %(src1)s, %(src2)s, %(dest)s, 226 %(dataSize)s, %(spm)d)''' % { 227 "class_name" : self.className, 228 "flags" : self.microFlagsText(microFlags), 229 "src1" : self.src1, "src2" : self.src2, 230 "dest" : self.dest, 231 "dataSize" : self.dataSize, 232 "spm" : self.spm} 233 234 class FpBinaryOp(X86Microop): 235 __metaclass__ = FpOpMeta 236 # This class itself doesn't act as a microop 237 abstract = True 238 239 # Default template parameter values 240 flag_code = "" 241 cond_check = "true" 242 else_code = ";" 243 op_class = "FloatAddOp" 244 245 def __init__(self, dest, src1, src2, spm=0, \ 246 SetStatus=False, UpdateFTW=True, dataSize="env.dataSize"): 247 self.dest = dest 248 self.src1 = src1 249 self.src2 = src2 250 self.spm = spm 251 self.dataSize = dataSize 252 if SetStatus: 253 self.className += "Flags" 254 if spm: 255 self.className += "Top" 256 if spm and UpdateFTW: 257 self.className += "Tag" 258 259 def getAllocator(self, microFlags): 260 return '''new %(class_name)s(machInst, macrocodeBlock, 261 %(flags)s, %(src1)s, %(src2)s, %(dest)s, 262 %(dataSize)s, %(spm)d)''' % { 263 "class_name" : self.className, 264 "flags" : self.microFlagsText(microFlags), 265 "src1" : self.src1, "src2" : self.src2, 266 "dest" : self.dest, 267 "dataSize" : self.dataSize, 268 "spm" : self.spm} 269 270 class Movfp(FpUnaryOp): 271 code = 'FpDestReg_uqw = FpSrcReg1_uqw;' 272 else_code = 'FpDestReg_uqw = FpDestReg_uqw;' 273 cond_check = "checkCondition(ccFlagBits | cfofBits | dfBit | \ 274 ecfBit | ezfBit, src2)" 275 op_class = 'IntAluOp' 276 277 class Xorfp(FpBinaryOp): 278 code = 'FpDestReg_uqw = FpSrcReg1_uqw ^ FpSrcReg2_uqw;' 279 280 class Sqrtfp(FpBinaryOp): 281 code = 'FpDestReg = sqrt(FpSrcReg2);' 282 op_class = 'FloatSqrtOp' 283 284 class Cosfp(FpUnaryOp): 285 code = 'FpDestReg = cos(FpSrcReg1);' 286 op_class = 'FloatSqrtOp' 287 288 class Sinfp(FpUnaryOp): 289 code = 'FpDestReg = sin(FpSrcReg1);' 290 op_class = 'FloatSqrtOp' 291 292 class Tanfp(FpUnaryOp): 293 code = 'FpDestReg = tan(FpSrcReg1);' 294 op_class = 'FloatSqrtOp' 295 296 297 # Conversion microops 298 class ConvOp(FpBinaryOp): 299 abstract = True 300 op_class = 'FloatCvtOp' 301 def __init__(self, dest, src1, **kwargs): 302 super(ConvOp, self).__init__(dest, src1, \ 303 "InstRegIndex(FLOATREG_MICROFP0)", \ 304 **kwargs) 305 306 # These probably shouldn't look at the ExtMachInst directly to figure 307 # out what size to use and should instead delegate that to the macroop's 308 # constructor. That would be more efficient, and it would make the 309 # microops a little more modular. 310 class cvtf_i2d(ConvOp): 311 code = ''' 312 X86IntReg intReg = SSrcReg1; 313 if (REX_W) 314 FpDestReg = intReg.SR; 315 else 316 FpDestReg = intReg.SE; 317 ''' 318 319 class cvtf_i2d_hi(ConvOp): 320 code = 'FpDestReg = bits(SSrcReg1, 63, 32);' 321 322 class cvtf_d2i(ConvOp): 323 code = ''' 324 int64_t intSrcReg1 = static_cast<int64_t>(FpSrcReg1); 325 if (REX_W) 326 SDestReg = intSrcReg1; 327 else 328 SDestReg = merge(SDestReg, intSrcReg1, 4); 329 ''' 330 331 # Convert two integers registers representing an 80-bit floating 332 # point number to an x87 register. 333 class cvtint_fp80(FpBinaryOp): 334 code = ''' 335 uint8_t bits[10]; 336 *(uint64_t *)(bits + 0) = SSrcReg1; 337 *(uint16_t *)(bits + 8) = (uint16_t)SSrcReg2; 338 FpDestReg = loadFloat80(bits); 339 ''' 340 341 # Convert an x87 register (double) into extended precision and 342 # extract the highest 64 bits. 343 class cvtfp80h_int(ConvOp): 344 code = ''' 345 char bits[10]; 346 storeFloat80(bits, FpSrcReg1); 347 SDestReg = *(uint64_t *)(bits + 0); 348 ''' 349 350 # Convert an x87 register (double) into extended precision and 351 # extract the lowest 16 bits. 352 class cvtfp80l_int(ConvOp): 353 code = ''' 354 char bits[10]; 355 storeFloat80(bits, FpSrcReg1); 356 SDestReg = *(uint16_t *)(bits + 8); 357 ''' 358 359 # These need to consider size at some point. They'll always use doubles 360 # for the moment. 361 class addfp(FpBinaryOp): 362 code = 'FpDestReg = FpSrcReg1 + FpSrcReg2;' 363 364 class mulfp(FpBinaryOp): 365 code = 'FpDestReg = FpSrcReg1 * FpSrcReg2;' 366 op_class = 'FloatMultOp' 367 368 class divfp(FpBinaryOp): 369 code = 'FpDestReg = FpSrcReg1 / FpSrcReg2;' 370 op_class = 'FloatDivOp' 371 372 class subfp(FpBinaryOp): 373 code = 'FpDestReg = FpSrcReg1 - FpSrcReg2;' 374 375 class Yl2xFp(FpBinaryOp): 376 code = ''' 377 FpDestReg = FpSrcReg2 * (log(FpSrcReg1) / log(2)); 378 ''' 379 op_class = 'FloatSqrtOp' 380 381 class PremFp(FpBinaryOp): 382 code = ''' 383 MiscReg new_fsw(FSW); 384 int src1_exp; 385 int src2_exp; 386 std::frexp(FpSrcReg1, &src1_exp); 387 std::frexp(FpSrcReg2, &src2_exp); 388 389 const int d(src2_exp - src1_exp); 390 if (d < 64) { 391 const int64_t q(std::trunc(FpSrcReg2 / FpSrcReg1)); 392 FpDestReg = FpSrcReg2 - FpSrcReg1 * q; 393 new_fsw &= ~(CC0Bit | CC1Bit | CC2Bit | CC2Bit); 394 new_fsw |= (q & 0x1) ? CC1Bit : 0; 395 new_fsw |= (q & 0x2) ? CC3Bit : 0; 396 new_fsw |= (q & 0x4) ? CC0Bit : 0; 397 } else { 398 const int n(42); 399 const int64_t qq(std::trunc( 400 FpSrcReg2 / std::ldexp(FpSrcReg1, d - n))); 401 FpDestReg = FpSrcReg2 - std::ldexp(FpSrcReg1 * qq, d - n); 402 new_fsw |= CC2Bit; 403 } 404 DPRINTF(X86, "src1: %lf, src2: %lf, dest: %lf, FSW: 0x%x\\n", 405 FpSrcReg1, FpSrcReg2, FpDestReg, new_fsw); 406 ''' 407 op_class = 'FloatDivOp' 408 409 flag_code = 'FSW = new_fsw;' 410 411 class Compfp(FpBinaryOp): 412 def __init__(self, src1, src2, spm=0, setStatus=False, updateFTW=True, \ 413 dataSize="env.dataSize"): 414 super(Compfp, self).__init__("InstRegIndex(FLOATREG_MICROFP0)", \ 415 src1, src2, spm, setStatus, updateFTW, dataSize) 416 # This class sets the condition codes in rflags according to the 417 # rules for comparing floating point. 418 code = ''' 419 // ZF PF CF 420 // Unordered 1 1 1 421 // Greater than 0 0 0 422 // Less than 0 0 1 423 // Equal 1 0 0 424 // OF = SF = AF = 0 425 ccFlagBits = ccFlagBits & ~(SFBit | AFBit | ZFBit | PFBit); 426 cfofBits = cfofBits & ~(OFBit | CFBit); 427 428 if (std::isnan(FpSrcReg1) || std::isnan(FpSrcReg2)) { 429 ccFlagBits = ccFlagBits | (ZFBit | PFBit); 430 cfofBits = cfofBits | CFBit; 431 } 432 else if(FpSrcReg1 < FpSrcReg2) 433 cfofBits = cfofBits | CFBit; 434 else if(FpSrcReg1 == FpSrcReg2) 435 ccFlagBits = ccFlagBits | ZFBit; 436 ''' 437 op_class = 'FloatCmpOp' 438 439 class absfp(FpUnaryOp): 440 code = 'FpDestReg = fabs(FpSrcReg1);' 441 flag_code = 'FSW = FSW & (~CC1Bit);' 442 443 class chsfp(FpUnaryOp): 444 code = 'FpDestReg = (-1) * (FpSrcReg1);' 445 flag_code = 'FSW = FSW & (~CC1Bit);' 446 447 class Pop87(FpUnaryOp): 448 def __init__(self, spm=1, UpdateFTW=True): 449 super(Pop87, self).__init__( \ 450 "InstRegIndex(FLOATREG_MICROFP0)", \ 451 "InstRegIndex(FLOATREG_MICROFP0)", \ 452 spm=spm, SetStatus=False, UpdateFTW=UpdateFTW) 453 454 code = '' 455 op_class = 'IntAluOp' 456}};
|