regop.isa revision 4732:9fdd1a5ab692
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 = "ccFlagBits = genFlags(ccFlagBits, ext, DestReg, SrcReg1, %s);"
330
331
332    # This creates a python representations of a microop which are a cross
333    # product of reg/immediate and flag/no flag versions.
334    def defineMicroRegOp(mnemonic, code, subtract = False, cc=False, elseCode=";"):
335        Name = mnemonic
336        name = mnemonic.lower()
337
338        # Find op2 in each of the instruction definitions. Create two versions
339        # of the code, one with an integer operand, and one with an immediate
340        # operand.
341        matcher = re.compile("op2(?P<typeQual>\\.\\w+)?")
342        regCode = matcher.sub("SrcReg2", code)
343        immCode = matcher.sub("imm8", code)
344
345        if subtract:
346            secondSrc = "-op2, true"
347        else:
348            secondSrc = "op2"
349
350        if not cc:
351            flagCode = genCCFlagBits % secondSrc
352            condCode = "true"
353        else:
354            flagCode = ""
355            condCode = checkCCFlagBits
356
357        regFlagCode = matcher.sub("SrcReg2", flagCode)
358        immFlagCode = matcher.sub("imm8", flagCode)
359
360        class RegOpChild(RegOp):
361            mnemonic = name
362            className = Name
363            def __init__(self, dest, src1, src2, flags=None, dataSize="env.dataSize"):
364                super(RegOpChild, self).__init__(dest, src1, src2, flags, dataSize)
365
366        microopClasses[name] = RegOpChild
367
368        setUpMicroRegOp(name, Name, "X86ISA::RegOp", regCode);
369        setUpMicroRegOp(name, Name + "Flags", "X86ISA::RegOp", regCode,
370                flagCode = regFlagCode, condCheck = condCode, elseCode = elseCode);
371
372        class RegOpChildImm(RegOpImm):
373            mnemonic = name + 'i'
374            className = Name + 'Imm'
375            def __init__(self, dest, src1, src2, flags=None, dataSize="env.dataSize"):
376                super(RegOpChildImm, self).__init__(dest, src1, src2, flags, dataSize)
377
378        microopClasses[name + 'i'] = RegOpChildImm
379
380        setUpMicroRegOp(name + "i", Name + "Imm", "X86ISA::RegOpImm", immCode);
381        setUpMicroRegOp(name + "i", Name + "ImmFlags", "X86ISA::RegOpImm", immCode,
382                flagCode = immFlagCode, condCheck = condCode, elseCode = elseCode);
383
384    # This has it's own function because Wr ops have implicit destinations
385    def defineMicroRegOpWr(mnemonic, code, elseCode=";"):
386        Name = mnemonic
387        name = mnemonic.lower()
388
389        # Find op2 in each of the instruction definitions. Create two versions
390        # of the code, one with an integer operand, and one with an immediate
391        # operand.
392        matcher = re.compile("op2(?P<typeQual>\\.\\w+)?")
393        regCode = matcher.sub("SrcReg2", code)
394        immCode = matcher.sub("imm8", code)
395
396        class RegOpChild(RegOp):
397            mnemonic = name
398            className = Name
399            def __init__(self, src1, src2, flags=None, dataSize="env.dataSize"):
400                super(RegOpChild, self).__init__("NUM_INTREGS", src1, src2, flags, dataSize)
401
402        microopClasses[name] = RegOpChild
403
404        setUpMicroRegOp(name, Name, "X86ISA::RegOp", regCode);
405        setUpMicroRegOp(name, Name + "Flags", "X86ISA::RegOp", regCode,
406                condCheck = checkCCFlagBits, elseCode = elseCode);
407
408        class RegOpChildImm(RegOpImm):
409            mnemonic = name + 'i'
410            className = Name + 'Imm'
411            def __init__(self, src1, src2, flags=None, dataSize="env.dataSize"):
412                super(RegOpChildImm, self).__init__("NUM_INTREGS", src1, src2, flags, dataSize)
413
414        microopClasses[name + 'i'] = RegOpChildImm
415
416        setUpMicroRegOp(name + 'i', Name + "Imm", "X86ISA::RegOpImm", immCode);
417        setUpMicroRegOp(name + 'i', Name + "ImmFlags", "X86ISA::RegOpImm", immCode,
418                condCheck = checkCCFlagBits, elseCode = elseCode);
419
420    # This has it's own function because Rd ops don't always have two parameters
421    def defineMicroRegOpRd(mnemonic, code):
422        Name = mnemonic
423        name = mnemonic.lower()
424
425        class RegOpChild(RegOp):
426            def __init__(self, dest, src1 = "NUM_INTREGS", dataSize="env.dataSize"):
427                super(RegOpChild, self).__init__(dest, src1, "NUM_INTREGS", None, dataSize)
428                self.className = Name
429                self.mnemonic = name
430
431        microopClasses[name] = RegOpChild
432
433        setUpMicroRegOp(name, Name, "X86ISA::RegOp", code);
434
435    def defineMicroRegOpImm(mnemonic, code):
436        Name = mnemonic
437        name = mnemonic.lower()
438
439        class RegOpChild(RegOpImm):
440            def __init__(self, dest, src1, src2, dataSize="env.dataSize"):
441                super(RegOpChild, self).__init__(dest, src1, src2, None, dataSize)
442                self.className = Name
443                self.mnemonic = name
444
445        microopClasses[name] = RegOpChild
446
447        setUpMicroRegOp(name, Name, "X86ISA::RegOpImm", code);
448
449    defineMicroRegOp('Add', 'DestReg = merge(DestReg, SrcReg1 + op2, dataSize)')
450    defineMicroRegOp('Or', 'DestReg = merge(DestReg, SrcReg1 | op2, dataSize)')
451    defineMicroRegOp('Adc', '''
452            CCFlagBits flags = ccFlagBits;
453            DestReg = merge(DestReg, SrcReg1 + op2 + flags.CF, dataSize);
454            ''')
455    defineMicroRegOp('Sbb', '''
456            CCFlagBits flags = ccFlagBits;
457            DestReg = merge(DestReg, SrcReg1 - op2 - flags.CF, dataSize);
458            ''', True)
459    defineMicroRegOp('And', 'DestReg = merge(DestReg, SrcReg1 & op2, dataSize)')
460    defineMicroRegOp('Sub', 'DestReg = merge(DestReg, SrcReg1 - op2, dataSize)', True)
461    defineMicroRegOp('Xor', 'DestReg = merge(DestReg, SrcReg1 ^ op2, dataSize)')
462    # defineMicroRegOp('Cmp', 'DestReg = merge(DestReg, DestReg - op2, dataSize)', True)
463    defineMicroRegOp('Mul1s', 'DestReg = merge(DestReg, DestReg * op2, dataSize)')
464    defineMicroRegOp('Mov', 'DestReg = merge(SrcReg1, op2, dataSize)',
465            elseCode='DestReg=DestReg;', cc=True)
466
467    # Shift instructions
468    defineMicroRegOp('Sll', '''
469            uint8_t shiftAmt = (op2 & ((dataSize == 8) ? mask(4) : mask(3)));
470            DestReg = merge(DestReg, SrcReg1 << shiftAmt, dataSize);
471            ''')
472    defineMicroRegOp('Srl', '''
473            uint8_t shiftAmt = (op2 & ((dataSize == 8) ? mask(4) : mask(3)));
474            // Because what happens to the bits shift -in- on a right shift
475            // is not defined in the C/C++ standard, we have to mask them out
476            // to be sure they're zero.
477            uint64_t logicalMask = mask(dataSize * 8 - shiftAmt);
478            DestReg = merge(DestReg, (SrcReg1 >> shiftAmt) & logicalMask, dataSize);
479            ''')
480    defineMicroRegOp('Sra', '''
481            uint8_t shiftAmt = (op2 & ((dataSize == 8) ? mask(4) : mask(3)));
482            // Because what happens to the bits shift -in- on a right shift
483            // is not defined in the C/C++ standard, we have to sign extend
484            // them manually to be sure.
485            uint64_t arithMask =
486                -bits(op2, dataSize * 8 - 1) << (dataSize * 8 - shiftAmt);
487            DestReg = merge(DestReg, (SrcReg1 >> shiftAmt) | arithMask, dataSize);
488            ''')
489    defineMicroRegOp('Ror', '''
490            uint8_t shiftAmt =
491                (op2 & ((dataSize == 8) ? mask(4) : mask(3)));
492            if(shiftAmt)
493            {
494                uint64_t top = SrcReg1 << (dataSize * 8 - shiftAmt);
495                uint64_t bottom = bits(SrcReg1, dataSize * 8, shiftAmt);
496                DestReg = merge(DestReg, top | bottom, dataSize);
497            }
498            else
499                DestReg = DestReg;
500            ''')
501    defineMicroRegOp('Rcr', '''
502            ''')
503    defineMicroRegOp('Rol', '''
504            uint8_t shiftAmt =
505                (op2 & ((dataSize == 8) ? mask(4) : mask(3)));
506            if(shiftAmt)
507            {
508                uint64_t top = SrcReg1 << shiftAmt;
509                uint64_t bottom =
510                    bits(SrcReg1, dataSize * 8 - 1, dataSize * 8 - shiftAmt);
511                DestReg = merge(DestReg, top | bottom, dataSize);
512            }
513            else
514                DestReg = DestReg;
515            ''')
516    defineMicroRegOp('Rcl', '''
517            ''')
518
519    defineMicroRegOpWr('Wrip', 'RIP = SrcReg1 + op2', elseCode="RIP = RIP;")
520
521    defineMicroRegOpRd('Rdip', 'DestReg = RIP')
522
523    defineMicroRegOpImm('Sext', '''
524            IntReg val = SrcReg1;
525            int sign_bit = bits(val, imm8-1, imm8-1);
526            val = sign_bit ? (val | ~mask(imm8)) : val;
527            DestReg = merge(DestReg, val, dataSize);''')
528
529    defineMicroRegOpImm('Zext', 'DestReg = bits(SrcReg1, imm8-1, 0);')
530}};
531