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