regop.isa revision 4688
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
77            //Write the resulting state to the execution context
78            if(fault == NoFault)
79            {
80                %(op_wb)s;
81            }
82            return fault;
83        }
84}};
85
86def template MicroRegOpImmExecute {{
87        Fault %(class_name)sImm::execute(%(CPU_exec_context)s *xc,
88                Trace::InstRecord *traceData) const
89        {
90            Fault fault = NoFault;
91
92            %(op_decl)s;
93            %(op_rd)s;
94
95            if(%(cond_check)s)
96            {
97                %(code)s;
98                %(flag_code)s;
99            }
100
101            //Write the resulting state to the execution context
102            if(fault == NoFault)
103            {
104                %(op_wb)s;
105            }
106            return fault;
107        }
108}};
109
110def template MicroRegOpDeclare {{
111    class %(class_name)s : public %(base_class)s
112    {
113      protected:
114        void buildMe();
115
116      public:
117        %(class_name)s(ExtMachInst _machInst,
118                const char * instMnem,
119                bool isMicro, bool isDelayed, bool isFirst, bool isLast,
120                RegIndex _src1, RegIndex _src2, RegIndex _dest,
121                uint8_t _dataSize, uint8_t _ext);
122
123        %(class_name)s(ExtMachInst _machInst,
124                const char * instMnem,
125                RegIndex _src1, RegIndex _src2, RegIndex _dest,
126                uint8_t _dataSize, uint8_t _ext);
127
128        %(BasicExecDeclare)s
129    };
130}};
131
132def template MicroRegOpImmDeclare {{
133
134    class %(class_name)sImm : public %(base_class)s
135    {
136      protected:
137        void buildMe();
138
139      public:
140        %(class_name)sImm(ExtMachInst _machInst,
141                const char * instMnem,
142                bool isMicro, bool isDelayed, bool isFirst, bool isLast,
143                RegIndex _src1, uint8_t _imm8, RegIndex _dest,
144                uint8_t _dataSize, uint8_t _ext);
145
146        %(class_name)sImm(ExtMachInst _machInst,
147                const char * instMnem,
148                RegIndex _src1, uint8_t _imm8, RegIndex _dest,
149                uint8_t _dataSize, uint8_t _ext);
150
151        %(BasicExecDeclare)s
152    };
153}};
154
155def template MicroRegOpConstructor {{
156
157    inline void %(class_name)s::buildMe()
158    {
159        %(constructor)s;
160    }
161
162    inline %(class_name)s::%(class_name)s(
163            ExtMachInst machInst, const char * instMnem,
164            RegIndex _src1, RegIndex _src2, RegIndex _dest,
165            uint8_t _dataSize, uint8_t _ext) :
166        %(base_class)s(machInst, "%(mnemonic)s", instMnem,
167                false, false, false, false,
168                _src1, _src2, _dest, _dataSize, _ext,
169                %(op_class)s)
170    {
171        buildMe();
172    }
173
174    inline %(class_name)s::%(class_name)s(
175            ExtMachInst machInst, const char * instMnem,
176            bool isMicro, bool isDelayed, bool isFirst, bool isLast,
177            RegIndex _src1, RegIndex _src2, RegIndex _dest,
178            uint8_t _dataSize, uint8_t _ext) :
179        %(base_class)s(machInst, "%(mnemonic)s", instMnem,
180                isMicro, isDelayed, isFirst, isLast,
181                _src1, _src2, _dest, _dataSize, _ext,
182                %(op_class)s)
183    {
184        buildMe();
185    }
186}};
187
188def template MicroRegOpImmConstructor {{
189
190    inline void %(class_name)sImm::buildMe()
191    {
192        %(constructor)s;
193    }
194
195    inline %(class_name)sImm::%(class_name)sImm(
196            ExtMachInst machInst, const char * instMnem,
197            RegIndex _src1, uint8_t _imm8, RegIndex _dest,
198            uint8_t _dataSize, uint8_t _ext) :
199        %(base_class)s(machInst, "%(mnemonic)s", instMnem,
200                false, false, false, false,
201                _src1, _imm8, _dest, _dataSize, _ext,
202                %(op_class)s)
203    {
204        buildMe();
205    }
206
207    inline %(class_name)sImm::%(class_name)sImm(
208            ExtMachInst machInst, const char * instMnem,
209            bool isMicro, bool isDelayed, bool isFirst, bool isLast,
210            RegIndex _src1, uint8_t _imm8, RegIndex _dest,
211            uint8_t _dataSize, uint8_t _ext) :
212        %(base_class)s(machInst, "%(mnemonic)s", instMnem,
213                isMicro, isDelayed, isFirst, isLast,
214                _src1, _imm8, _dest, _dataSize, _ext,
215                %(op_class)s)
216    {
217        buildMe();
218    }
219}};
220
221let {{
222    class X86MicroMeta(type):
223        def __new__(mcls, name, bases, dict):
224            abstract = False
225            if "abstract" in dict:
226                abstract = dict['abstract']
227                del dict['abstract']
228
229            cls = type.__new__(mcls, name, bases, dict)
230            if not abstract:
231                allClasses[name] = cls
232            return cls
233
234    class XXX86Microop(object):
235        __metaclass__ = X86MicroMeta
236        abstract = True
237
238    class RegOp(X86Microop):
239        abstract = True
240        def __init__(self, dest, src1, src2, flags):
241            self.dest = dest
242            self.src1 = src1
243            self.src2 = src2
244            self.flags = flags
245            self.dataSize = "env.dataSize"
246            if flags is None:
247                self.ext = 0
248            else:
249                if not isinstance(flags, (list, tuple)):
250                    raise Exception, "flags must be a list or tuple of flags"
251                self.ext = " | ".join(flags)
252                self.className += "Flags"
253
254        def getAllocator(self, *microFlags):
255            allocator = '''new %(class_name)s(machInst, mnemonic
256                    %(flags)s, %(src1)s, %(src2)s, %(dest)s,
257                    %(dataSize)s, %(ext)s)''' % {
258                "class_name" : self.className,
259                "flags" : self.microFlagsText(microFlags),
260                "src1" : self.src1, "src2" : self.src2,
261                "dest" : self.dest,
262                "dataSize" : self.dataSize,
263                "ext" : self.ext}
264            return allocator
265
266    class RegOpImm(X86Microop):
267        abstract = True
268        def __init__(self, dest, src1, imm8, flags):
269            self.dest = dest
270            self.src1 = src1
271            self.imm8 = imm8
272            self.flags = flags
273            self.dataSize = "env.dataSize"
274            if flags is None:
275                self.ext = 0
276            else:
277                if not isinstance(flags, (list, tuple)):
278                    raise Exception, "flags must be a list or tuple of flags"
279                self.ext = " | ".join(flags)
280                self.className += "Flags"
281
282        def getAllocator(self, *microFlags):
283            allocator = '''new %(class_name)s(machInst, mnemonic
284                    %(flags)s, %(src1)s, %(imm8)s, %(dest)s,
285                    %(dataSize)s, %(ext)s)''' % {
286                "class_name" : self.className,
287                "flags" : self.microFlagsText(microFlags),
288                "src1" : self.src1, "imm8" : self.imm8,
289                "dest" : self.dest,
290                "dataSize" : self.dataSize,
291                "ext" : self.ext}
292            return allocator
293}};
294
295let {{
296
297    # Make these empty strings so that concatenating onto
298    # them will always work.
299    header_output = ""
300    decoder_output = ""
301    exec_output = ""
302
303    # A function which builds the C++ classes that implement the microops
304    def setUpMicroRegOp(name, Name, base, code, flagCode, condCheck):
305        global header_output
306        global decoder_output
307        global exec_output
308        global microopClasses
309
310        iop = InstObjParams(name, Name, base,
311                {"code" : code,
312                 "flag_code" : flagCode,
313                 "cond_check" : condCheck})
314        header_output += MicroRegOpDeclare.subst(iop)
315        decoder_output += MicroRegOpConstructor.subst(iop)
316        exec_output += MicroRegOpExecute.subst(iop)
317
318
319    checkCCFlagBits = "checkCondition(ccFlagBits)"
320    genCCFlagBits = "ccFlagBits = genFlags(ccFlagBits, ext, DestReg, SrcReg1, %s);"
321
322
323    # This creates a python representations of a microop which are a cross
324    # product of reg/immediate and flag/no flag versions.
325    def defineMicroRegOp(mnemonic, code, secondSrc = "op2", cc=False):
326        Name = mnemonic
327        name = mnemonic.lower()
328
329        # Find op2 in each of the instruction definitions. Create two versions
330        # of the code, one with an integer operand, and one with an immediate
331        # operand.
332        matcher = re.compile("op2(?P<typeQual>\\.\\w+)?")
333        regCode = matcher.sub("SrcReg2", code)
334        immCode = matcher.sub("imm8", code)
335
336        if not cc:
337            flagCode = genCCFlagBits % secondSrc
338            condCode = "true"
339        else:
340            flagCode = ""
341            condCode = checkCCFlagBits
342
343        regFlagCode = matcher.sub("SrcReg2", flagCode)
344        immFlagCode = matcher.sub("imm8", flagCode)
345
346        class RegOpChild(RegOp):
347            mnemonic = name
348            className = Name
349            def __init__(self, dest, src1, src2, flags=None):
350                super(RegOpChild, self).__init__(dest, src1, src2, flags)
351
352        microopClasses[name] = RegOpChild
353
354        setUpMicroRegOp(name, Name, "X86ISA::RegOp", regCode, "", "true");
355        setUpMicroRegOp(name, Name + "Flags", "X86ISA::RegOp", regCode, regFlagCode, condCode);
356
357        class RegOpChildImm(RegOpImm):
358            mnemonic = name + 'i'
359            className = Name + 'Imm'
360            def __init__(self, dest, src1, src2, flags=None):
361                super(RegOpChildImm, self).__init__(dest, src1, src2, flags)
362
363        microopClasses[name + 'i'] = RegOpChildImm
364
365        setUpMicroRegOp(name + "i", Name + "Imm", "X86ISA::RegOpImm", immCode, "", "true");
366        setUpMicroRegOp(name + "i", Name + "ImmFlags", "X86ISA::RegOpImm", immCode, immFlagCode, condCode);
367
368    defineMicroRegOp('Add', 'DestReg = merge(DestReg, SrcReg1 + op2, dataSize)')
369    defineMicroRegOp('Or', 'DestReg = merge(DestReg, SrcReg1 | op2, dataSize)')
370    defineMicroRegOp('Adc', 'DestReg = merge(DestReg, SrcReg1 + op2, dataSize)')
371    defineMicroRegOp('Sbb', 'DestReg = merge(DestReg, SrcReg1 - op2, dataSize)', '-op2')
372    defineMicroRegOp('And', 'DestReg = merge(DestReg, SrcReg1 & op2, dataSize)')
373    defineMicroRegOp('Sub', 'DestReg = merge(DestReg, SrcReg1 - op2, dataSize)', '-op2')
374    defineMicroRegOp('Xor', 'DestReg = merge(DestReg, SrcReg1 ^ op2, dataSize)')
375    defineMicroRegOp('Cmp', 'DestReg = merge(DestReg, DestReg - op2, dataSize)', '-op2')
376    defineMicroRegOp('Mov', 'DestReg = merge(SrcReg1, op2, dataSize)', cc=True)
377
378    # This has it's own function because Wr ops have implicit destinations
379    def defineMicroRegOpWr(mnemonic, code):
380        Name = mnemonic
381        name = mnemonic.lower()
382
383        # Find op2 in each of the instruction definitions. Create two versions
384        # of the code, one with an integer operand, and one with an immediate
385        # operand.
386        matcher = re.compile("op2(?P<typeQual>\\.\\w+)?")
387        regCode = matcher.sub("SrcReg2", code)
388        immCode = matcher.sub("imm8", code)
389
390        class RegOpChild(RegOp):
391            mnemonic = name
392            className = Name
393            def __init__(self, src1, src2, flags=None):
394                super(RegOpChild, self).__init__("NUM_INTREGS", src1, src2, flags)
395
396        microopClasses[name] = RegOpChild
397
398        setUpMicroRegOp(name, Name, "X86ISA::RegOp", regCode, "", "true");
399        setUpMicroRegOp(name, Name + "Flags", "X86ISA::RegOp", regCode, "", checkCCFlagBits);
400
401        class RegOpChildImm(RegOpImm):
402            mnemonic = name
403            className = Name
404            def __init__(self, src1, src2):
405                super(RegOpChildImm, self).__init__("NUM_INTREGS", src1, src2, None)
406
407        microopClasses[name + 'i'] = RegOpChildImm
408
409        setUpMicroRegOp(name + 'i', Name + "Imm", "X86ISA::RegOpImm", immCode, "", "true");
410        setUpMicroRegOp(name + 'i', Name + "ImmFlags", "X86ISA::RegOpImm", immCode, "", checkCCFlagBits);
411
412    defineMicroRegOpWr('Wrip', 'RIP = SrcReg1 + op2')
413
414    # This has it's own function because Rd ops don't always have two parameters
415    def defineMicroRegOpRd(mnemonic, code):
416        Name = mnemonic
417        name = mnemonic.lower()
418
419        class RegOpChild(RegOp):
420            def __init__(self, dest, src1 = "NUM_INTREGS"):
421                super(RegOpChild, self).__init__(dest, src1, "NUM_INTREGS", None)
422                self.className = Name
423                self.mnemonic = name
424
425        microopClasses[name] = RegOpChild
426
427        setUpMicroRegOp(name, Name, "X86ISA::RegOp", code, "", "true");
428
429    defineMicroRegOpRd('Rdip', 'DestReg = RIP')
430
431    def defineMicroRegOpImm(mnemonic, code):
432        Name = mnemonic
433        name = mnemonic.lower()
434
435        class RegOpChild(RegOpImm):
436            def __init__(self, dest, src1, src2):
437                super(RegOpChild, self).__init__(dest, src1, src2, None)
438                self.className = Name
439                self.mnemonic = name
440
441        microopClasses[name] = RegOpChild
442
443        setUpMicroRegOp(name, Name, "X86ISA::RegOpImm", code, "", "true");
444
445    defineMicroRegOpImm('Sext', '''
446            IntReg val = SrcReg1;
447            int sign_bit = bits(val, imm8-1, imm8-1);
448            val = sign_bit ? (val | ~mask(imm8)) : val;
449            DestReg = merge(DestReg, val, dataSize);''')
450}};
451