regop.isa revision 7626
1// Copyright (c) 2007-2008 The Hewlett-Packard Development Company
2// All rights reserved.
3//
4// The license below extends only to copyright in the software and shall
5// not be construed as granting a license to any other intellectual
6// property including but not limited to intellectual property relating
7// to a hardware implementation of the functionality of the software
8// licensed hereunder.  You may use the software subject to the license
9// terms below provided that you ensure that this notice is replicated
10// unmodified and in its entirety in all distributions of the software,
11// modified or unmodified, in source code or in binary form.
12//
13// Redistribution and use in source and binary forms, with or without
14// modification, are permitted provided that the following conditions are
15// met: redistributions of source code must retain the above copyright
16// notice, this list of conditions and the following disclaimer;
17// redistributions in binary form must reproduce the above copyright
18// notice, this list of conditions and the following disclaimer in the
19// documentation and/or other materials provided with the distribution;
20// neither the name of the copyright holders nor the names of its
21// contributors may be used to endorse or promote products derived from
22// this software without specific prior written permission.
23//
24// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35//
36// Authors: Gabe Black
37
38//////////////////////////////////////////////////////////////////////////
39//
40// RegOp Microop templates
41//
42//////////////////////////////////////////////////////////////////////////
43
44def template MicroRegOpExecute {{
45        Fault %(class_name)s::execute(%(CPU_exec_context)s *xc,
46                Trace::InstRecord *traceData) const
47        {
48            Fault fault = NoFault;
49
50            DPRINTF(X86, "The data size is %d\n", dataSize);
51            %(op_decl)s;
52            %(op_rd)s;
53
54            if(%(cond_check)s)
55            {
56                %(code)s;
57                %(flag_code)s;
58            }
59            else
60            {
61                %(else_code)s;
62            }
63
64            //Write the resulting state to the execution context
65            if(fault == NoFault)
66            {
67                %(op_wb)s;
68            }
69            return fault;
70        }
71}};
72
73def template MicroRegOpImmExecute {{
74        Fault %(class_name)s::execute(%(CPU_exec_context)s *xc,
75                Trace::InstRecord *traceData) const
76        {
77            Fault fault = NoFault;
78
79            %(op_decl)s;
80            %(op_rd)s;
81
82            if(%(cond_check)s)
83            {
84                %(code)s;
85                %(flag_code)s;
86            }
87            else
88            {
89                %(else_code)s;
90            }
91
92            //Write the resulting state to the execution context
93            if(fault == NoFault)
94            {
95                %(op_wb)s;
96            }
97            return fault;
98        }
99}};
100
101def template MicroRegOpDeclare {{
102    class %(class_name)s : public %(base_class)s
103    {
104      public:
105        %(class_name)s(ExtMachInst _machInst,
106                const char * instMnem, uint64_t setFlags,
107                InstRegIndex _src1, InstRegIndex _src2, InstRegIndex _dest,
108                uint8_t _dataSize, uint16_t _ext);
109
110        %(BasicExecDeclare)s
111    };
112}};
113
114def template MicroRegOpImmDeclare {{
115
116    class %(class_name)s : public %(base_class)s
117    {
118      public:
119        %(class_name)s(ExtMachInst _machInst,
120                const char * instMnem, uint64_t setFlags,
121                InstRegIndex _src1, uint8_t _imm8, InstRegIndex _dest,
122                uint8_t _dataSize, uint16_t _ext);
123
124        %(BasicExecDeclare)s
125    };
126}};
127
128def template MicroRegOpConstructor {{
129    inline %(class_name)s::%(class_name)s(
130            ExtMachInst machInst, const char * instMnem, uint64_t setFlags,
131            InstRegIndex _src1, InstRegIndex _src2, InstRegIndex _dest,
132            uint8_t _dataSize, uint16_t _ext) :
133        %(base_class)s(machInst, "%(mnemonic)s", instMnem, setFlags,
134                _src1, _src2, _dest, _dataSize, _ext,
135                %(op_class)s)
136    {
137        %(constructor)s;
138    }
139}};
140
141def template MicroRegOpImmConstructor {{
142    inline %(class_name)s::%(class_name)s(
143            ExtMachInst machInst, const char * instMnem, uint64_t setFlags,
144            InstRegIndex _src1, uint8_t _imm8, InstRegIndex _dest,
145            uint8_t _dataSize, uint16_t _ext) :
146        %(base_class)s(machInst, "%(mnemonic)s", instMnem, setFlags,
147                _src1, _imm8, _dest, _dataSize, _ext,
148                %(op_class)s)
149    {
150        %(constructor)s;
151    }
152}};
153
154output header {{
155    void
156    divide(uint64_t dividend, uint64_t divisor,
157            uint64_t &quotient, uint64_t &remainder);
158
159    enum SegmentSelectorCheck {
160      SegNoCheck, SegCSCheck, SegCallGateCheck, SegIntGateCheck,
161      SegSoftIntGateCheck, SegSSCheck, SegIretCheck, SegIntCSCheck,
162      SegTRCheck, SegTSSCheck, SegInGDTCheck, SegLDTCheck
163    };
164
165    enum LongModeDescriptorType {
166        LDT64 = 2,
167        AvailableTSS64 = 9,
168        BusyTSS64 = 0xb,
169        CallGate64 = 0xc,
170        IntGate64 = 0xe,
171        TrapGate64 = 0xf
172    };
173}};
174
175output decoder {{
176    void
177    divide(uint64_t dividend, uint64_t divisor,
178            uint64_t &quotient, uint64_t &remainder)
179    {
180        //Check for divide by zero.
181        if (divisor == 0)
182            panic("Divide by zero!\\n");
183        //If the divisor is bigger than the dividend, don't do anything.
184        if (divisor <= dividend) {
185            //Shift the divisor so it's msb lines up with the dividend.
186            int dividendMsb = findMsbSet(dividend);
187            int divisorMsb = findMsbSet(divisor);
188            int shift = dividendMsb - divisorMsb;
189            divisor <<= shift;
190            //Compute what we'll add to the quotient if the divisor isn't
191            //now larger than the dividend.
192            uint64_t quotientBit = 1;
193            quotientBit <<= shift;
194            //If we need to step back a bit (no pun intended) because the
195            //divisor got too to large, do that here. This is the "or two"
196            //part of one or two bit division.
197            if (divisor > dividend) {
198                quotientBit >>= 1;
199                divisor >>= 1;
200            }
201            //Decrement the remainder and increment the quotient.
202            quotient += quotientBit;
203            remainder -= divisor;
204        }
205    }
206}};
207
208let {{
209    # Make these empty strings so that concatenating onto
210    # them will always work.
211    header_output = ""
212    decoder_output = ""
213    exec_output = ""
214
215    immTemplates = (
216            MicroRegOpImmDeclare,
217            MicroRegOpImmConstructor,
218            MicroRegOpImmExecute)
219
220    regTemplates = (
221            MicroRegOpDeclare,
222            MicroRegOpConstructor,
223            MicroRegOpExecute)
224
225    class RegOpMeta(type):
226        def buildCppClasses(self, name, Name, suffix, \
227                code, flag_code, cond_check, else_code):
228
229            # Globals to stick the output in
230            global header_output
231            global decoder_output
232            global exec_output
233
234            # Stick all the code together so it can be searched at once
235            allCode = "|".join((code, flag_code, cond_check, else_code))
236
237            # If op2 is used anywhere, make register and immediate versions
238            # of this code.
239            matcher = re.compile("(?<!\\w)(?P<prefix>s?)op2(?P<typeQual>\\.\\w+)?")
240            match = matcher.search(allCode)
241            if match:
242                typeQual = ""
243                if match.group("typeQual"):
244                    typeQual = match.group("typeQual")
245                src2_name = "%spsrc2%s" % (match.group("prefix"), typeQual)
246                self.buildCppClasses(name, Name, suffix,
247                        matcher.sub(src2_name, code),
248                        matcher.sub(src2_name, flag_code),
249                        matcher.sub(src2_name, cond_check),
250                        matcher.sub(src2_name, else_code))
251                imm_name = "%simm8" % match.group("prefix")
252                self.buildCppClasses(name + "i", Name, suffix + "Imm",
253                        matcher.sub(imm_name, code),
254                        matcher.sub(imm_name, flag_code),
255                        matcher.sub(imm_name, cond_check),
256                        matcher.sub(imm_name, else_code))
257                return
258
259            # If there's something optional to do with flags, generate
260            # a version without it and fix up this version to use it.
261            if flag_code != "" or cond_check != "true":
262                self.buildCppClasses(name, Name, suffix,
263                        code, "", "true", else_code)
264                suffix = "Flags" + suffix
265
266            # If psrc1 or psrc2 is used, we need to actually insert code to
267            # compute it.
268            matcher = re.compile("(?<!\w)psrc1(?!\w)")
269            if matcher.search(allCode):
270                code = "uint64_t psrc1 = pick(SrcReg1, 0, dataSize);" + code
271            matcher = re.compile("(?<!\w)psrc2(?!\w)")
272            if matcher.search(allCode):
273                code = "uint64_t psrc2 = pick(SrcReg2, 1, dataSize);" + code
274            # Also make available versions which do sign extension
275            matcher = re.compile("(?<!\w)spsrc1(?!\w)")
276            if matcher.search(allCode):
277                code = "int64_t spsrc1 = signedPick(SrcReg1, 0, dataSize);" + code
278            matcher = re.compile("(?<!\w)spsrc2(?!\w)")
279            if matcher.search(allCode):
280                code = "int64_t spsrc2 = signedPick(SrcReg2, 1, dataSize);" + code
281            matcher = re.compile("(?<!\w)simm8(?!\w)")
282            if matcher.search(allCode):
283                code = "int8_t simm8 = imm8;" + code
284
285            base = "X86ISA::RegOp"
286
287            # If imm8 shows up in the code, use the immediate templates, if
288            # not, hopefully the register ones will be correct.
289            templates = regTemplates
290            matcher = re.compile("(?<!\w)s?imm8(?!\w)")
291            if matcher.search(allCode):
292                base += "Imm"
293                templates = immTemplates
294
295            # Get everything ready for the substitution
296            iop = InstObjParams(name, Name + suffix, base,
297                    {"code" : code,
298                     "flag_code" : flag_code,
299                     "cond_check" : cond_check,
300                     "else_code" : else_code})
301
302            # Generate the actual code (finally!)
303            header_output += templates[0].subst(iop)
304            decoder_output += templates[1].subst(iop)
305            exec_output += templates[2].subst(iop)
306
307
308        def __new__(mcls, Name, bases, dict):
309            abstract = False
310            name = Name.lower()
311            if "abstract" in dict:
312                abstract = dict['abstract']
313                del dict['abstract']
314
315            cls = super(RegOpMeta, mcls).__new__(mcls, Name, bases, dict)
316            if not abstract:
317                cls.className = Name
318                cls.base_mnemonic = name
319                code = cls.code
320                flag_code = cls.flag_code
321                cond_check = cls.cond_check
322                else_code = cls.else_code
323
324                # Set up the C++ classes
325                mcls.buildCppClasses(cls, name, Name, "",
326                        code, flag_code, cond_check, else_code)
327
328                # Hook into the microassembler dict
329                global microopClasses
330                microopClasses[name] = cls
331
332                allCode = "|".join((code, flag_code, cond_check, else_code))
333
334                # If op2 is used anywhere, make register and immediate versions
335                # of this code.
336                matcher = re.compile("op2(?P<typeQual>\\.\\w+)?")
337                if matcher.search(allCode):
338                    microopClasses[name + 'i'] = cls
339            return cls
340
341
342    class RegOp(X86Microop):
343        __metaclass__ = RegOpMeta
344        # This class itself doesn't act as a microop
345        abstract = True
346
347        # Default template parameter values
348        flag_code = ""
349        cond_check = "true"
350        else_code = ";"
351
352        def __init__(self, dest, src1, op2, flags = None, dataSize = "env.dataSize"):
353            self.dest = dest
354            self.src1 = src1
355            self.op2 = op2
356            self.flags = flags
357            self.dataSize = dataSize
358            if flags is None:
359                self.ext = 0
360            else:
361                if not isinstance(flags, (list, tuple)):
362                    raise Exception, "flags must be a list or tuple of flags"
363                self.ext = " | ".join(flags)
364                self.className += "Flags"
365
366        def getAllocator(self, microFlags):
367            className = self.className
368            if self.mnemonic == self.base_mnemonic + 'i':
369                className += "Imm"
370            allocator = '''new %(class_name)s(machInst, macrocodeBlock,
371                    %(flags)s, %(src1)s, %(op2)s, %(dest)s,
372                    %(dataSize)s, %(ext)s)''' % {
373                "class_name" : className,
374                "flags" : self.microFlagsText(microFlags),
375                "src1" : self.src1, "op2" : self.op2,
376                "dest" : self.dest,
377                "dataSize" : self.dataSize,
378                "ext" : self.ext}
379            return allocator
380
381    class LogicRegOp(RegOp):
382        abstract = True
383        flag_code = '''
384            //Don't have genFlags handle the OF or CF bits
385            uint64_t mask = CFBit | ECFBit | OFBit;
386            ccFlagBits = genFlags(ccFlagBits, ext & ~mask, DestReg, psrc1, op2);
387            //If a logic microop wants to set these, it wants to set them to 0.
388            ccFlagBits &= ~(CFBit & ext);
389            ccFlagBits &= ~(ECFBit & ext);
390            ccFlagBits &= ~(OFBit & ext);
391        '''
392
393    class FlagRegOp(RegOp):
394        abstract = True
395        flag_code = \
396            "ccFlagBits = genFlags(ccFlagBits, ext, DestReg, psrc1, op2);"
397
398    class SubRegOp(RegOp):
399        abstract = True
400        flag_code = \
401            "ccFlagBits = genFlags(ccFlagBits, ext, DestReg, psrc1, ~op2, true);"
402
403    class CondRegOp(RegOp):
404        abstract = True
405        cond_check = "checkCondition(ccFlagBits, ext)"
406
407    class RdRegOp(RegOp):
408        abstract = True
409        def __init__(self, dest, src1=None, dataSize="env.dataSize"):
410            if not src1:
411                src1 = dest
412            super(RdRegOp, self).__init__(dest, src1, \
413                    "InstRegIndex(NUM_INTREGS)", None, dataSize)
414
415    class WrRegOp(RegOp):
416        abstract = True
417        def __init__(self, src1, src2, flags=None, dataSize="env.dataSize"):
418            super(WrRegOp, self).__init__("InstRegIndex(NUM_INTREGS)", \
419                    src1, src2, flags, dataSize)
420
421    class Add(FlagRegOp):
422        code = 'DestReg = merge(DestReg, psrc1 + op2, dataSize);'
423
424    class Or(LogicRegOp):
425        code = 'DestReg = merge(DestReg, psrc1 | op2, dataSize);'
426
427    class Adc(FlagRegOp):
428        code = '''
429            CCFlagBits flags = ccFlagBits;
430            DestReg = merge(DestReg, psrc1 + op2 + flags.cf, dataSize);
431            '''
432
433    class Sbb(SubRegOp):
434        code = '''
435            CCFlagBits flags = ccFlagBits;
436            DestReg = merge(DestReg, psrc1 - op2 - flags.cf, dataSize);
437            '''
438
439    class And(LogicRegOp):
440        code = 'DestReg = merge(DestReg, psrc1 & op2, dataSize)'
441
442    class Sub(SubRegOp):
443        code = 'DestReg = merge(DestReg, psrc1 - op2, dataSize)'
444
445    class Xor(LogicRegOp):
446        code = 'DestReg = merge(DestReg, psrc1 ^ op2, dataSize)'
447
448    class Mul1s(WrRegOp):
449        code = '''
450            ProdLow = psrc1 * op2;
451            int halfSize = (dataSize * 8) / 2;
452            uint64_t shifter = (ULL(1) << halfSize);
453            uint64_t hiResult;
454            uint64_t psrc1_h = psrc1 / shifter;
455            uint64_t psrc1_l = psrc1 & mask(halfSize);
456            uint64_t psrc2_h = (op2 / shifter) & mask(halfSize);
457            uint64_t psrc2_l = op2 & mask(halfSize);
458            hiResult = ((psrc1_l * psrc2_h + psrc1_h * psrc2_l +
459                        ((psrc1_l * psrc2_l) / shifter)) /shifter) +
460                       psrc1_h * psrc2_h;
461            if (bits(psrc1, dataSize * 8 - 1))
462                hiResult -= op2;
463            if (bits(op2, dataSize * 8 - 1))
464                hiResult -= psrc1;
465            ProdHi = hiResult;
466            '''
467        flag_code = '''
468            if ((-ProdHi & mask(dataSize * 8)) !=
469                    bits(ProdLow, dataSize * 8 - 1)) {
470                ccFlagBits = ccFlagBits | (ext & (CFBit | OFBit | ECFBit));
471            } else {
472                ccFlagBits = ccFlagBits & ~(ext & (CFBit | OFBit | ECFBit));
473            }
474        '''
475
476    class Mul1u(WrRegOp):
477        code = '''
478            ProdLow = psrc1 * op2;
479            int halfSize = (dataSize * 8) / 2;
480            uint64_t shifter = (ULL(1) << halfSize);
481            uint64_t psrc1_h = psrc1 / shifter;
482            uint64_t psrc1_l = psrc1 & mask(halfSize);
483            uint64_t psrc2_h = (op2 / shifter) & mask(halfSize);
484            uint64_t psrc2_l = op2 & mask(halfSize);
485            ProdHi = ((psrc1_l * psrc2_h + psrc1_h * psrc2_l +
486                      ((psrc1_l * psrc2_l) / shifter)) / shifter) +
487                     psrc1_h * psrc2_h;
488            '''
489        flag_code = '''
490            if (ProdHi) {
491                ccFlagBits = ccFlagBits | (ext & (CFBit | OFBit | ECFBit));
492            } else {
493                ccFlagBits = ccFlagBits & ~(ext & (CFBit | OFBit | ECFBit));
494            }
495        '''
496
497    class Mulel(RdRegOp):
498        code = 'DestReg = merge(SrcReg1, ProdLow, dataSize);'
499
500    class Muleh(RdRegOp):
501        def __init__(self, dest, src1=None, flags=None, dataSize="env.dataSize"):
502            if not src1:
503                src1 = dest
504            super(RdRegOp, self).__init__(dest, src1, \
505                    "InstRegIndex(NUM_INTREGS)", flags, dataSize)
506        code = 'DestReg = merge(SrcReg1, ProdHi, dataSize);'
507
508    # One or two bit divide
509    class Div1(WrRegOp):
510        code = '''
511            //These are temporaries so that modifying them later won't make
512            //the ISA parser think they're also sources.
513            uint64_t quotient = 0;
514            uint64_t remainder = psrc1;
515            //Similarly, this is a temporary so changing it doesn't make it
516            //a source.
517            uint64_t divisor = op2;
518            //This is a temporary just for consistency and clarity.
519            uint64_t dividend = remainder;
520            //Do the division.
521            divide(dividend, divisor, quotient, remainder);
522            //Record the final results.
523            Remainder = remainder;
524            Quotient = quotient;
525            Divisor = divisor;
526            '''
527
528    # Step divide
529    class Div2(RegOp):
530        code = '''
531            uint64_t dividend = Remainder;
532            uint64_t divisor = Divisor;
533            uint64_t quotient = Quotient;
534            uint64_t remainder = dividend;
535            int remaining = op2;
536            //If we overshot, do nothing. This lets us unrool division loops a
537            //little.
538            if (remaining) {
539                if (divisor & (ULL(1) << 63)) {
540                    while (remaining && !(dividend & (ULL(1) << 63))) {
541                        dividend = (dividend << 1) |
542                            bits(SrcReg1, remaining - 1);
543                        quotient <<= 1;
544                        remaining--;
545                    }
546                    if (dividend & (ULL(1) << 63)) {
547                        bool highBit = false;
548                        if (dividend < divisor && remaining) {
549                            highBit = true;
550                            dividend = (dividend << 1) |
551                                bits(SrcReg1, remaining - 1);
552                            quotient <<= 1;
553                            remaining--;
554                        }
555                        if (highBit || divisor <= dividend) {
556                            quotient++;
557                            dividend -= divisor;
558                        }
559                    }
560                    remainder = dividend;
561                } else {
562                    //Shift in bits from the low order portion of the dividend
563                    while (dividend < divisor && remaining) {
564                        dividend = (dividend << 1) |
565                            bits(SrcReg1, remaining - 1);
566                        quotient <<= 1;
567                        remaining--;
568                    }
569                    remainder = dividend;
570                    //Do the division.
571                    divide(dividend, divisor, quotient, remainder);
572                }
573            }
574            //Keep track of how many bits there are still to pull in.
575            DestReg = merge(DestReg, remaining, dataSize);
576            //Record the final results
577            Remainder = remainder;
578            Quotient = quotient;
579        '''
580        flag_code = '''
581            if (remaining == 0)
582                ccFlagBits = ccFlagBits | (ext & EZFBit);
583            else
584                ccFlagBits = ccFlagBits & ~(ext & EZFBit);
585        '''
586
587    class Divq(RdRegOp):
588        code = 'DestReg = merge(SrcReg1, Quotient, dataSize);'
589
590    class Divr(RdRegOp):
591        code = 'DestReg = merge(SrcReg1, Remainder, dataSize);'
592
593    class Mov(CondRegOp):
594        code = 'DestReg = merge(SrcReg1, op2, dataSize)'
595        else_code = 'DestReg = DestReg;'
596
597    # Shift instructions
598
599    class Sll(RegOp):
600        code = '''
601            uint8_t shiftAmt = (op2 & ((dataSize == 8) ? mask(6) : mask(5)));
602            DestReg = merge(DestReg, psrc1 << shiftAmt, dataSize);
603            '''
604        flag_code = '''
605            // If the shift amount is zero, no flags should be modified.
606            if (shiftAmt) {
607                //Zero out any flags we might modify. This way we only have to
608                //worry about setting them.
609                ccFlagBits = ccFlagBits & ~(ext & (CFBit | ECFBit | OFBit));
610                int CFBits = 0;
611                //Figure out if we -would- set the CF bits if requested.
612                if (shiftAmt <= dataSize * 8 &&
613                        bits(SrcReg1, dataSize * 8 - shiftAmt)) {
614                    CFBits = 1;
615                }
616                //If some combination of the CF bits need to be set, set them.
617                if ((ext & (CFBit | ECFBit)) && CFBits)
618                    ccFlagBits = ccFlagBits | (ext & (CFBit | ECFBit));
619                //Figure out what the OF bit should be.
620                if ((ext & OFBit) && (CFBits ^ bits(DestReg, dataSize * 8 - 1)))
621                    ccFlagBits = ccFlagBits | OFBit;
622                //Use the regular mechanisms to calculate the other flags.
623                ccFlagBits = genFlags(ccFlagBits, ext & ~(CFBit | ECFBit | OFBit),
624                        DestReg, psrc1, op2);
625            }
626        '''
627
628    class Srl(RegOp):
629        code = '''
630            uint8_t shiftAmt = (op2 & ((dataSize == 8) ? mask(6) : mask(5)));
631            // Because what happens to the bits shift -in- on a right shift
632            // is not defined in the C/C++ standard, we have to mask them out
633            // to be sure they're zero.
634            uint64_t logicalMask = mask(dataSize * 8 - shiftAmt);
635            DestReg = merge(DestReg, (psrc1 >> shiftAmt) & logicalMask, dataSize);
636            '''
637        flag_code = '''
638            // If the shift amount is zero, no flags should be modified.
639            if (shiftAmt) {
640                //Zero out any flags we might modify. This way we only have to
641                //worry about setting them.
642                ccFlagBits = ccFlagBits & ~(ext & (CFBit | ECFBit | OFBit));
643                //If some combination of the CF bits need to be set, set them.
644                if ((ext & (CFBit | ECFBit)) && 
645                        shiftAmt <= dataSize * 8 &&
646                        bits(SrcReg1, shiftAmt - 1)) {
647                    ccFlagBits = ccFlagBits | (ext & (CFBit | ECFBit));
648                }
649                //Figure out what the OF bit should be.
650                if ((ext & OFBit) && bits(SrcReg1, dataSize * 8 - 1))
651                    ccFlagBits = ccFlagBits | OFBit;
652                //Use the regular mechanisms to calculate the other flags.
653                ccFlagBits = genFlags(ccFlagBits, ext & ~(CFBit | ECFBit | OFBit),
654                        DestReg, psrc1, op2);
655            }
656        '''
657
658    class Sra(RegOp):
659        code = '''
660            uint8_t shiftAmt = (op2 & ((dataSize == 8) ? mask(6) : mask(5)));
661            // Because what happens to the bits shift -in- on a right shift
662            // is not defined in the C/C++ standard, we have to sign extend
663            // them manually to be sure.
664            uint64_t arithMask = (shiftAmt == 0) ? 0 :
665                -bits(psrc1, dataSize * 8 - 1) << (dataSize * 8 - shiftAmt);
666            DestReg = merge(DestReg, (psrc1 >> shiftAmt) | arithMask, dataSize);
667            '''
668        flag_code = '''
669            // If the shift amount is zero, no flags should be modified.
670            if (shiftAmt) {
671                //Zero out any flags we might modify. This way we only have to
672                //worry about setting them.
673                ccFlagBits = ccFlagBits & ~(ext & (CFBit | ECFBit | OFBit));
674                //If some combination of the CF bits need to be set, set them.
675                uint8_t effectiveShift =
676                    (shiftAmt <= dataSize * 8) ? shiftAmt : (dataSize * 8);
677                if ((ext & (CFBit | ECFBit)) &&
678                        bits(SrcReg1, effectiveShift - 1)) {
679                    ccFlagBits = ccFlagBits | (ext & (CFBit | ECFBit));
680                }
681                //Use the regular mechanisms to calculate the other flags.
682                ccFlagBits = genFlags(ccFlagBits, ext & ~(CFBit | ECFBit | OFBit),
683                        DestReg, psrc1, op2);
684            }
685        '''
686
687    class Ror(RegOp):
688        code = '''
689            uint8_t shiftAmt =
690                (op2 & ((dataSize == 8) ? mask(6) : mask(5)));
691            uint8_t realShiftAmt = shiftAmt % (dataSize * 8);
692            if(realShiftAmt)
693            {
694                uint64_t top = psrc1 << (dataSize * 8 - realShiftAmt);
695                uint64_t bottom = bits(psrc1, dataSize * 8, realShiftAmt);
696                DestReg = merge(DestReg, top | bottom, dataSize);
697            }
698            else
699                DestReg = merge(DestReg, DestReg, dataSize);
700            '''
701        flag_code = '''
702            // If the shift amount is zero, no flags should be modified.
703            if (shiftAmt) {
704                //Zero out any flags we might modify. This way we only have to
705                //worry about setting them.
706                ccFlagBits = ccFlagBits & ~(ext & (CFBit | ECFBit | OFBit));
707                //Find the most and second most significant bits of the result.
708                int msb = bits(DestReg, dataSize * 8 - 1);
709                int smsb = bits(DestReg, dataSize * 8 - 2);
710                //If some combination of the CF bits need to be set, set them.
711                if ((ext & (CFBit | ECFBit)) && msb)
712                    ccFlagBits = ccFlagBits | (ext & (CFBit | ECFBit));
713                //Figure out what the OF bit should be.
714                if ((ext & OFBit) && (msb ^ smsb))
715                    ccFlagBits = ccFlagBits | OFBit;
716                //Use the regular mechanisms to calculate the other flags.
717                ccFlagBits = genFlags(ccFlagBits, ext & ~(CFBit | ECFBit | OFBit),
718                        DestReg, psrc1, op2);
719            }
720        '''
721
722    class Rcr(RegOp):
723        code = '''
724            uint8_t shiftAmt =
725                (op2 & ((dataSize == 8) ? mask(6) : mask(5)));
726            uint8_t realShiftAmt = shiftAmt % (dataSize * 8 + 1);
727            if(realShiftAmt)
728            {
729                CCFlagBits flags = ccFlagBits;
730                uint64_t top = flags.cf << (dataSize * 8 - realShiftAmt);
731                if (realShiftAmt > 1)
732                    top |= psrc1 << (dataSize * 8 - realShiftAmt + 1);
733                uint64_t bottom = bits(psrc1, dataSize * 8 - 1, realShiftAmt);
734                DestReg = merge(DestReg, top | bottom, dataSize);
735            }
736            else
737                DestReg = merge(DestReg, DestReg, dataSize);
738            '''
739        flag_code = '''
740            // If the shift amount is zero, no flags should be modified.
741            if (shiftAmt) {
742                int origCFBit = (ccFlagBits & CFBit) ? 1 : 0;
743                //Zero out any flags we might modify. This way we only have to
744                //worry about setting them.
745                ccFlagBits = ccFlagBits & ~(ext & (CFBit | ECFBit | OFBit));
746                //Figure out what the OF bit should be.
747                if ((ext & OFBit) && (origCFBit ^
748                                      bits(SrcReg1, dataSize * 8 - 1))) {
749                    ccFlagBits = ccFlagBits | OFBit;
750                }
751                //If some combination of the CF bits need to be set, set them.
752                if ((ext & (CFBit | ECFBit)) &&
753                        (realShiftAmt == 0) ? origCFBit :
754                        bits(SrcReg1, realShiftAmt - 1)) {
755                    ccFlagBits = ccFlagBits | (ext & (CFBit | ECFBit));
756                }
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            uint8_t realShiftAmt = shiftAmt % (dataSize * 8);
768            if(realShiftAmt)
769            {
770                uint64_t top = psrc1 << realShiftAmt;
771                uint64_t bottom =
772                    bits(psrc1, dataSize * 8 - 1, dataSize * 8 - realShiftAmt);
773                DestReg = merge(DestReg, top | bottom, dataSize);
774            }
775            else
776                DestReg = merge(DestReg, DestReg, dataSize);
777            '''
778        flag_code = '''
779            // If the shift amount is zero, no flags should be modified.
780            if (shiftAmt) {
781                //Zero out any flags we might modify. This way we only have to
782                //worry about setting them.
783                ccFlagBits = ccFlagBits & ~(ext & (CFBit | ECFBit | OFBit));
784                //The CF bits, if set, would be set to the lsb of the result.
785                int lsb = DestReg & 0x1;
786                int msb = bits(DestReg, dataSize * 8 - 1);
787                //If some combination of the CF bits need to be set, set them.
788                if ((ext & (CFBit | ECFBit)) && lsb)
789                    ccFlagBits = ccFlagBits | (ext & (CFBit | ECFBit));
790                //Figure out what the OF bit should be.
791                if ((ext & OFBit) && (msb ^ lsb))
792                    ccFlagBits = ccFlagBits | OFBit;
793                //Use the regular mechanisms to calculate the other flags.
794                ccFlagBits = genFlags(ccFlagBits, ext & ~(CFBit | ECFBit | OFBit),
795                        DestReg, psrc1, op2);
796            }
797        '''
798
799    class Rcl(RegOp):
800        code = '''
801            uint8_t shiftAmt =
802                (op2 & ((dataSize == 8) ? mask(6) : mask(5)));
803            uint8_t realShiftAmt = shiftAmt % (dataSize * 8 + 1);
804            if(realShiftAmt)
805            {
806                CCFlagBits flags = ccFlagBits;
807                uint64_t top = psrc1 << realShiftAmt;
808                uint64_t bottom = flags.cf << (realShiftAmt - 1);
809                if(shiftAmt > 1)
810                    bottom |=
811                        bits(psrc1, dataSize * 8 - 1,
812                                   dataSize * 8 - realShiftAmt + 1);
813                DestReg = merge(DestReg, top | bottom, dataSize);
814            }
815            else
816                DestReg = merge(DestReg, DestReg, dataSize);
817            '''
818        flag_code = '''
819            // If the shift amount is zero, no flags should be modified.
820            if (shiftAmt) {
821                int origCFBit = (ccFlagBits & CFBit) ? 1 : 0;
822                //Zero out any flags we might modify. This way we only have to
823                //worry about setting them.
824                ccFlagBits = ccFlagBits & ~(ext & (CFBit | ECFBit | OFBit));
825                int msb = bits(DestReg, dataSize * 8 - 1);
826                int CFBits = bits(SrcReg1, dataSize * 8 - realShiftAmt);
827                //If some combination of the CF bits need to be set, set them.
828                if ((ext & (CFBit | ECFBit)) && 
829                        (realShiftAmt == 0) ? origCFBit : CFBits)
830                    ccFlagBits = ccFlagBits | (ext & (CFBit | ECFBit));
831                //Figure out what the OF bit should be.
832                if ((ext & OFBit) && (msb ^ CFBits))
833                    ccFlagBits = ccFlagBits | OFBit;
834                //Use the regular mechanisms to calculate the other flags.
835                ccFlagBits = genFlags(ccFlagBits, ext & ~(CFBit | ECFBit | OFBit),
836                        DestReg, psrc1, op2);
837            }
838        '''
839
840    class Sld(RegOp):
841        code = '''
842            uint8_t shiftAmt = (op2 & ((dataSize == 8) ? mask(6) : mask(5)));
843            uint8_t dataBits = dataSize * 8;
844            uint8_t realShiftAmt = shiftAmt % (2 * dataBits);
845            uint64_t result;
846            if (realShiftAmt == 0) {
847                result = psrc1;
848            } else if (realShiftAmt < dataBits) {
849                result = (psrc1 << realShiftAmt) |
850                         (DoubleBits >> (dataBits - realShiftAmt));
851            } else {
852                result = (DoubleBits << (realShiftAmt - dataBits)) |
853                         (psrc1 >> (2 * dataBits - realShiftAmt));
854            }
855            DestReg = merge(DestReg, result, dataSize);
856            '''
857        flag_code = '''
858            // If the shift amount is zero, no flags should be modified.
859            if (shiftAmt) {
860                //Zero out any flags we might modify. This way we only have to
861                //worry about setting them.
862                ccFlagBits = ccFlagBits & ~(ext & (CFBit | ECFBit | OFBit));
863                int CFBits = 0;
864                //Figure out if we -would- set the CF bits if requested.
865                if ((realShiftAmt == 0 &&
866                        bits(DoubleBits, 0)) ||
867                    (realShiftAmt <= dataBits &&
868                     bits(SrcReg1, dataBits - realShiftAmt)) ||
869                    (realShiftAmt > dataBits &&
870                     bits(DoubleBits, 2 * dataBits - realShiftAmt))) {
871                    CFBits = 1;
872                }
873                //If some combination of the CF bits need to be set, set them.
874                if ((ext & (CFBit | ECFBit)) && CFBits)
875                    ccFlagBits = ccFlagBits | (ext & (CFBit | ECFBit));
876                //Figure out what the OF bit should be.
877                if ((ext & OFBit) && (bits(SrcReg1, dataBits - 1) ^
878                                      bits(result, dataBits - 1)))
879                    ccFlagBits = ccFlagBits | OFBit;
880                //Use the regular mechanisms to calculate the other flags.
881                ccFlagBits = genFlags(ccFlagBits, ext & ~(CFBit | ECFBit | OFBit),
882                        DestReg, psrc1, op2);
883            }
884        '''
885
886    class Srd(RegOp):
887        code = '''
888            uint8_t shiftAmt = (op2 & ((dataSize == 8) ? mask(6) : mask(5)));
889            uint8_t dataBits = dataSize * 8;
890            uint8_t realShiftAmt = shiftAmt % (2 * dataBits);
891            uint64_t result;
892            if (realShiftAmt == 0) {
893                result = psrc1;
894            } else if (realShiftAmt < dataBits) {
895                // Because what happens to the bits shift -in- on a right
896                // shift is not defined in the C/C++ standard, we have to
897                // mask them out to be sure they're zero.
898                uint64_t logicalMask = mask(dataBits - realShiftAmt);
899                result = ((psrc1 >> realShiftAmt) & logicalMask) |
900                         (DoubleBits << (dataBits - realShiftAmt));
901            } else {
902                uint64_t logicalMask = mask(2 * dataBits - realShiftAmt);
903                result = ((DoubleBits >> (realShiftAmt - dataBits)) &
904                          logicalMask) |
905                         (psrc1 << (2 * dataBits - realShiftAmt));
906            }
907            DestReg = merge(DestReg, result, dataSize);
908            '''
909        flag_code = '''
910            // If the shift amount is zero, no flags should be modified.
911            if (shiftAmt) {
912                //Zero out any flags we might modify. This way we only have to
913                //worry about setting them.
914                ccFlagBits = ccFlagBits & ~(ext & (CFBit | ECFBit | OFBit));
915                int CFBits = 0;
916                //If some combination of the CF bits need to be set, set them.
917                if ((realShiftAmt == 0 &&
918                            bits(DoubleBits, dataBits - 1)) ||
919                        (realShiftAmt <= dataBits &&
920                         bits(SrcReg1, realShiftAmt - 1)) ||
921                        (realShiftAmt > dataBits &&
922                         bits(DoubleBits, realShiftAmt - dataBits - 1))) {
923                    CFBits = 1;
924                }
925                //If some combination of the CF bits need to be set, set them.
926                if ((ext & (CFBit | ECFBit)) && CFBits)
927                    ccFlagBits = ccFlagBits | (ext & (CFBit | ECFBit));
928                //Figure out what the OF bit should be.
929                if ((ext & OFBit) && (bits(SrcReg1, dataBits - 1) ^
930                                      bits(result, dataBits - 1)))
931                    ccFlagBits = ccFlagBits | OFBit;
932                //Use the regular mechanisms to calculate the other flags.
933                ccFlagBits = genFlags(ccFlagBits, ext & ~(CFBit | ECFBit | OFBit),
934                        DestReg, psrc1, op2);
935            }
936        '''
937
938    class Mdb(WrRegOp):
939        code = 'DoubleBits = psrc1 ^ op2;'
940
941    class Wrip(WrRegOp, CondRegOp):
942        code = 'RIP = psrc1 + sop2 + CSBase'
943        else_code="RIP = RIP;"
944
945    class Wruflags(WrRegOp):
946        code = 'ccFlagBits = psrc1 ^ op2'
947
948    class Wrflags(WrRegOp):
949        code = '''
950            MiscReg newFlags = psrc1 ^ op2;
951            MiscReg userFlagMask = 0xDD5;
952            // Get only the user flags
953            ccFlagBits = newFlags & userFlagMask;
954            // Get everything else
955            nccFlagBits = newFlags & ~userFlagMask;
956        '''
957
958    class Rdip(RdRegOp):
959        code = 'DestReg = RIP - CSBase'
960
961    class Ruflags(RdRegOp):
962        code = 'DestReg = ccFlagBits'
963
964    class Rflags(RdRegOp):
965        code = 'DestReg = ccFlagBits | nccFlagBits'
966
967    class Ruflag(RegOp):
968        code = '''
969            int flag = bits(ccFlagBits, imm8);
970            DestReg = merge(DestReg, flag, dataSize);
971            ccFlagBits = (flag == 0) ? (ccFlagBits | EZFBit) :
972                                       (ccFlagBits & ~EZFBit);
973            '''
974        def __init__(self, dest, imm, flags=None, \
975                dataSize="env.dataSize"):
976            super(Ruflag, self).__init__(dest, \
977                    "InstRegIndex(NUM_INTREGS)", imm, flags, dataSize)
978
979    class Rflag(RegOp):
980        code = '''
981            MiscReg flagMask = 0x3F7FDD5;
982            MiscReg flags = (nccFlagBits | ccFlagBits) & flagMask;
983            int flag = bits(flags, imm8);
984            DestReg = merge(DestReg, flag, dataSize);
985            ccFlagBits = (flag == 0) ? (ccFlagBits | EZFBit) :
986                                       (ccFlagBits & ~EZFBit);
987            '''
988        def __init__(self, dest, imm, flags=None, \
989                dataSize="env.dataSize"):
990            super(Rflag, self).__init__(dest, \
991                    "InstRegIndex(NUM_INTREGS)", imm, flags, dataSize)
992
993    class Sext(RegOp):
994        code = '''
995            IntReg val = psrc1;
996            // Mask the bit position so that it wraps.
997            int bitPos = op2 & (dataSize * 8 - 1);
998            int sign_bit = bits(val, bitPos, bitPos);
999            uint64_t maskVal = mask(bitPos+1);
1000            val = sign_bit ? (val | ~maskVal) : (val & maskVal);
1001            DestReg = merge(DestReg, val, dataSize);
1002            '''
1003        flag_code = '''
1004            if (!sign_bit)
1005                ccFlagBits = ccFlagBits &
1006                    ~(ext & (CFBit | ECFBit | ZFBit | EZFBit));
1007            else
1008                ccFlagBits = ccFlagBits |
1009                    (ext & (CFBit | ECFBit | ZFBit | EZFBit));
1010            '''
1011
1012    class Zext(RegOp):
1013        code = 'DestReg = merge(DestReg, bits(psrc1, op2, 0), dataSize);'
1014
1015    class Rddr(RegOp):
1016        def __init__(self, dest, src1, flags=None, dataSize="env.dataSize"):
1017            super(Rddr, self).__init__(dest, \
1018                    src1, "InstRegIndex(NUM_INTREGS)", flags, dataSize)
1019        code = '''
1020            CR4 cr4 = CR4Op;
1021            DR7 dr7 = DR7Op;
1022            if ((cr4.de == 1 && (src1 == 4 || src1 == 5)) || src1 >= 8) {
1023                fault = new InvalidOpcode();
1024            } else if (dr7.gd) {
1025                fault = new DebugException();
1026            } else {
1027                DestReg = merge(DestReg, DebugSrc1, dataSize);
1028            }
1029        '''
1030
1031    class Wrdr(RegOp):
1032        def __init__(self, dest, src1, flags=None, dataSize="env.dataSize"):
1033            super(Wrdr, self).__init__(dest, \
1034                    src1, "InstRegIndex(NUM_INTREGS)", flags, dataSize)
1035        code = '''
1036            CR4 cr4 = CR4Op;
1037            DR7 dr7 = DR7Op;
1038            if ((cr4.de == 1 && (dest == 4 || dest == 5)) || dest >= 8) {
1039                fault = new InvalidOpcode();
1040            } else if ((dest == 6 || dest == 7) && bits(psrc1, 63, 32) &&
1041                    machInst.mode.mode == LongMode) {
1042                fault = new GeneralProtection(0);
1043            } else if (dr7.gd) {
1044                fault = new DebugException();
1045            } else {
1046                DebugDest = psrc1;
1047            }
1048        '''
1049
1050    class Rdcr(RegOp):
1051        def __init__(self, dest, src1, flags=None, dataSize="env.dataSize"):
1052            super(Rdcr, self).__init__(dest, \
1053                    src1, "InstRegIndex(NUM_INTREGS)", flags, dataSize)
1054        code = '''
1055            if (src1 == 1 || (src1 > 4 && src1 < 8) || (src1 > 8)) {
1056                fault = new InvalidOpcode();
1057            } else {
1058                DestReg = merge(DestReg, ControlSrc1, dataSize);
1059            }
1060        '''
1061
1062    class Wrcr(RegOp):
1063        def __init__(self, dest, src1, flags=None, dataSize="env.dataSize"):
1064            super(Wrcr, self).__init__(dest, \
1065                    src1, "InstRegIndex(NUM_INTREGS)", flags, dataSize)
1066        code = '''
1067            if (dest == 1 || (dest > 4 && dest < 8) || (dest > 8)) {
1068                fault = new InvalidOpcode();
1069            } else {
1070                // There are *s in the line below so it doesn't confuse the
1071                // parser. They may be unnecessary.
1072                //Mis*cReg old*Val = pick(Cont*rolDest, 0, dat*aSize);
1073                MiscReg newVal = psrc1;
1074
1075                // Check for any modifications that would cause a fault.
1076                switch(dest) {
1077                  case 0:
1078                    {
1079                        Efer efer = EferOp;
1080                        CR0 cr0 = newVal;
1081                        CR4 oldCr4 = CR4Op;
1082                        if (bits(newVal, 63, 32) ||
1083                                (!cr0.pe && cr0.pg) ||
1084                                (!cr0.cd && cr0.nw) ||
1085                                (cr0.pg && efer.lme && !oldCr4.pae))
1086                            fault = new GeneralProtection(0);
1087                    }
1088                    break;
1089                  case 2:
1090                    break;
1091                  case 3:
1092                    break;
1093                  case 4:
1094                    {
1095                        CR4 cr4 = newVal;
1096                        // PAE can't be disabled in long mode.
1097                        if (bits(newVal, 63, 11) ||
1098                                (machInst.mode.mode == LongMode && !cr4.pae))
1099                            fault = new GeneralProtection(0);
1100                    }
1101                    break;
1102                  case 8:
1103                    {
1104                        if (bits(newVal, 63, 4))
1105                            fault = new GeneralProtection(0);
1106                    }
1107                  default:
1108                    panic("Unrecognized control register %d.\\n", dest);
1109                }
1110                ControlDest = newVal;
1111            }
1112            '''
1113
1114    # Microops for manipulating segmentation registers
1115    class SegOp(CondRegOp):
1116        abstract = True
1117        def __init__(self, dest, src1, flags=None, dataSize="env.dataSize"):
1118            super(SegOp, self).__init__(dest, \
1119                    src1, "InstRegIndex(NUM_INTREGS)", flags, dataSize)
1120
1121    class Wrbase(SegOp):
1122        code = '''
1123            SegBaseDest = psrc1;
1124        '''
1125
1126    class Wrlimit(SegOp):
1127        code = '''
1128            SegLimitDest = psrc1;
1129        '''
1130
1131    class Wrsel(SegOp):
1132        code = '''
1133            SegSelDest = psrc1;
1134        '''
1135
1136    class WrAttr(SegOp):
1137        code = '''
1138            SegAttrDest = psrc1;
1139        '''
1140
1141    class Rdbase(SegOp):
1142        code = '''
1143            DestReg = merge(DestReg, SegBaseSrc1, dataSize);
1144        '''
1145
1146    class Rdlimit(SegOp):
1147        code = '''
1148            DestReg = merge(DestReg, SegLimitSrc1, dataSize);
1149        '''
1150
1151    class RdAttr(SegOp):
1152        code = '''
1153            DestReg = merge(DestReg, SegAttrSrc1, dataSize);
1154        '''
1155
1156    class Rdsel(SegOp):
1157        code = '''
1158            DestReg = merge(DestReg, SegSelSrc1, dataSize);
1159        '''
1160
1161    class Rdval(RegOp):
1162        def __init__(self, dest, src1, flags=None, dataSize="env.dataSize"):
1163            super(Rdval, self).__init__(dest, src1, \
1164                    "InstRegIndex(NUM_INTREGS)", flags, dataSize)
1165        code = '''
1166            DestReg = MiscRegSrc1;
1167        '''
1168
1169    class Wrval(RegOp):
1170        def __init__(self, dest, src1, flags=None, dataSize="env.dataSize"):
1171            super(Wrval, self).__init__(dest, src1, \
1172                    "InstRegIndex(NUM_INTREGS)", flags, dataSize)
1173        code = '''
1174            MiscRegDest = SrcReg1;
1175        '''
1176
1177    class Chks(RegOp):
1178        def __init__(self, dest, src1, src2=0,
1179                flags=None, dataSize="env.dataSize"):
1180            super(Chks, self).__init__(dest,
1181                    src1, src2, flags, dataSize)
1182        code = '''
1183            // The selector is in source 1 and can be at most 16 bits.
1184            SegSelector selector = DestReg;
1185            SegDescriptor desc = SrcReg1;
1186            HandyM5Reg m5reg = M5Reg;
1187
1188            switch (imm8)
1189            {
1190              case SegNoCheck:
1191                break;
1192              case SegCSCheck:
1193                // Make sure it's the right type
1194                if (desc.s == 0 || desc.type.codeOrData != 1) {
1195                    fault = new GeneralProtection(0);
1196                } else if (m5reg.cpl != desc.dpl) {
1197                    fault = new GeneralProtection(0);
1198                }
1199                break;
1200              case SegCallGateCheck:
1201                panic("CS checks for far calls/jumps through call gates"
1202                        "not implemented.\\n");
1203                break;
1204              case SegSoftIntGateCheck:
1205                // Check permissions.
1206                if (desc.dpl < m5reg.cpl) {
1207                    fault = new GeneralProtection(selector);
1208                    break;
1209                }
1210                // Fall through on purpose
1211              case SegIntGateCheck:
1212                // Make sure the gate's the right type.
1213                if ((m5reg.mode == LongMode && (desc.type & 0xe) != 0xe) ||
1214                        ((desc.type & 0x6) != 0x6)) {
1215                    fault = new GeneralProtection(0);
1216                }
1217                break;
1218              case SegSSCheck:
1219                if (selector.si || selector.ti) {
1220                    if (!desc.p) {
1221                        fault = new StackFault(selector);
1222                    }
1223                } else {
1224                    if ((m5reg.submode != SixtyFourBitMode ||
1225                                m5reg.cpl == 3) ||
1226                            !(desc.s == 1 &&
1227                            desc.type.codeOrData == 0 && desc.type.w) ||
1228                            (desc.dpl != m5reg.cpl) ||
1229                            (selector.rpl != m5reg.cpl)) {
1230                        fault = new GeneralProtection(selector);
1231                    }
1232                }
1233                break;
1234              case SegIretCheck:
1235                {
1236                    if ((!selector.si && !selector.ti) ||
1237                            (selector.rpl < m5reg.cpl) ||
1238                            !(desc.s == 1 && desc.type.codeOrData == 1) ||
1239                            (!desc.type.c && desc.dpl != selector.rpl) ||
1240                            (desc.type.c && desc.dpl > selector.rpl)) {
1241                        fault = new GeneralProtection(selector);
1242                    } else if (!desc.p) {
1243                        fault = new SegmentNotPresent(selector);
1244                    }
1245                    break;
1246                }
1247              case SegIntCSCheck:
1248                if (m5reg.mode == LongMode) {
1249                    if (desc.l != 1 || desc.d != 0) {
1250                        fault = new GeneralProtection(selector);
1251                    }
1252                } else {
1253                    panic("Interrupt CS checks not implemented "
1254                            "in legacy mode.\\n");
1255                }
1256                break;
1257              case SegTRCheck:
1258                if (!selector.si || selector.ti) {
1259                    fault = new GeneralProtection(selector);
1260                }
1261                break;
1262              case SegTSSCheck:
1263                if (!desc.p) {
1264                    fault = new SegmentNotPresent(selector);
1265                } else if (!(desc.type == 0x9 ||
1266                        (desc.type == 1 &&
1267                         m5reg.mode != LongMode))) {
1268                    fault = new GeneralProtection(selector);
1269                }
1270                break;
1271              case SegInGDTCheck:
1272                if (selector.ti) {
1273                    fault = new GeneralProtection(selector);
1274                }
1275                break;
1276              case SegLDTCheck:
1277                if (!desc.p) {
1278                    fault = new SegmentNotPresent(selector);
1279                } else if (desc.type != 0x2) {
1280                    fault = new GeneralProtection(selector);
1281                }
1282                break;
1283              default:
1284                panic("Undefined segment check type.\\n");
1285            }
1286        '''
1287        flag_code = '''
1288            // Check for a NULL selector and set ZF,EZF appropriately.
1289            ccFlagBits = ccFlagBits & ~(ext & (ZFBit | EZFBit));
1290            if (!selector.si && !selector.ti)
1291                ccFlagBits = ccFlagBits | (ext & (ZFBit | EZFBit));
1292        '''
1293
1294    class Wrdh(RegOp):
1295        code = '''
1296            SegDescriptor desc = SrcReg1;
1297
1298            uint64_t target = bits(SrcReg2, 31, 0) << 32;
1299            switch(desc.type) {
1300              case LDT64:
1301              case AvailableTSS64:
1302              case BusyTSS64:
1303                replaceBits(target, 23, 0, desc.baseLow);
1304                replaceBits(target, 31, 24, desc.baseHigh);
1305                break;
1306              case CallGate64:
1307              case IntGate64:
1308              case TrapGate64:
1309                replaceBits(target, 15, 0, bits(desc, 15, 0));
1310                replaceBits(target, 31, 16, bits(desc, 63, 48));
1311                break;
1312              default:
1313                panic("Wrdh used with wrong descriptor type!\\n");
1314            }
1315            DestReg = target;
1316        '''
1317
1318    class Wrtsc(WrRegOp):
1319        code = '''
1320            TscOp = psrc1;
1321        '''
1322
1323    class Rdtsc(RdRegOp):
1324        code = '''
1325            DestReg = TscOp;
1326        '''
1327
1328    class Rdm5reg(RdRegOp):
1329        code = '''
1330            DestReg = M5Reg;
1331        '''
1332
1333    class Wrdl(RegOp):
1334        code = '''
1335            SegDescriptor desc = SrcReg1;
1336            SegSelector selector = SrcReg2;
1337            if (selector.si || selector.ti) {
1338                if (!desc.p)
1339                    panic("Segment not present.\\n");
1340                SegAttr attr = 0;
1341                attr.dpl = desc.dpl;
1342                attr.unusable = 0;
1343                attr.defaultSize = desc.d;
1344                attr.longMode = desc.l;
1345                attr.avl = desc.avl;
1346                attr.granularity = desc.g;
1347                attr.present = desc.p;
1348                attr.system = desc.s;
1349                attr.type = desc.type;
1350                if (!desc.s) {
1351                    // The expand down bit happens to be set for gates.
1352                    if (desc.type.e) {
1353                        panic("Gate descriptor encountered.\\n");
1354                    }
1355                    attr.readable = 1;
1356                    attr.writable = 1;
1357                    attr.expandDown = 0;
1358                } else {
1359                    if (desc.type.codeOrData) {
1360                        attr.expandDown = 0;
1361                        attr.readable = desc.type.r;
1362                        attr.writable = 0;
1363                    } else {
1364                        attr.expandDown = desc.type.e;
1365                        attr.readable = 1;
1366                        attr.writable = desc.type.w;
1367                    }
1368                }
1369                Addr base = desc.baseLow | (desc.baseHigh << 24);
1370                Addr limit = desc.limitLow | (desc.limitHigh << 16);
1371                if (desc.g)
1372                    limit = (limit << 12) | mask(12);
1373                SegBaseDest = base;
1374                SegLimitDest = limit;
1375                SegAttrDest = attr;
1376            } else {
1377                SegBaseDest = SegBaseDest;
1378                SegLimitDest = SegLimitDest;
1379                SegAttrDest = SegAttrDest;
1380            }
1381        '''
1382}};
1383