regop.isa revision 4712
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, 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, secondSrc = "op2", 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 not cc:
346            flagCode = genCCFlagBits % secondSrc
347            condCode = "true"
348        else:
349            flagCode = ""
350            condCode = checkCCFlagBits
351
352        regFlagCode = matcher.sub("SrcReg2", flagCode)
353        immFlagCode = matcher.sub("imm8", flagCode)
354
355        class RegOpChild(RegOp):
356            mnemonic = name
357            className = Name
358            def __init__(self, dest, src1, src2, flags=None, dataSize="env.dataSize"):
359                super(RegOpChild, self).__init__(dest, src1, src2, flags, dataSize)
360
361        microopClasses[name] = RegOpChild
362
363        setUpMicroRegOp(name, Name, "X86ISA::RegOp", regCode, "", "true", elseCode);
364        setUpMicroRegOp(name, Name + "Flags", "X86ISA::RegOp", regCode, regFlagCode, condCode, elseCode);
365
366        class RegOpChildImm(RegOpImm):
367            mnemonic = name + 'i'
368            className = Name + 'Imm'
369            def __init__(self, dest, src1, src2, flags=None, dataSize="env.dataSize"):
370                super(RegOpChildImm, self).__init__(dest, src1, src2, flags, dataSize)
371
372        microopClasses[name + 'i'] = RegOpChildImm
373
374        setUpMicroRegOp(name + "i", Name + "Imm", "X86ISA::RegOpImm", immCode, "", "true", elseCode);
375        setUpMicroRegOp(name + "i", Name + "ImmFlags", "X86ISA::RegOpImm", immCode, immFlagCode, condCode, elseCode);
376
377    defineMicroRegOp('Add', 'DestReg = merge(DestReg, SrcReg1 + op2, dataSize)')
378    defineMicroRegOp('Or', 'DestReg = merge(DestReg, SrcReg1 | op2, dataSize)')
379    defineMicroRegOp('Adc', 'DestReg = merge(DestReg, SrcReg1 + op2, dataSize)')
380    defineMicroRegOp('Sbb', 'DestReg = merge(DestReg, SrcReg1 - op2, dataSize)', '-op2')
381    defineMicroRegOp('And', 'DestReg = merge(DestReg, SrcReg1 & op2, dataSize)')
382    defineMicroRegOp('Sub', 'DestReg = merge(DestReg, SrcReg1 - op2, dataSize)', '-op2')
383    defineMicroRegOp('Xor', 'DestReg = merge(DestReg, SrcReg1 ^ op2, dataSize)')
384    defineMicroRegOp('Cmp', 'DestReg = merge(DestReg, DestReg - op2, dataSize)', '-op2')
385    defineMicroRegOp('Mov', 'DestReg = merge(SrcReg1, op2, dataSize)',
386            elseCode='DestReg=DestReg;', cc=True)
387
388    # This has it's own function because Wr ops have implicit destinations
389    def defineMicroRegOpWr(mnemonic, code, elseCode=";"):
390        Name = mnemonic
391        name = mnemonic.lower()
392
393        # Find op2 in each of the instruction definitions. Create two versions
394        # of the code, one with an integer operand, and one with an immediate
395        # operand.
396        matcher = re.compile("op2(?P<typeQual>\\.\\w+)?")
397        regCode = matcher.sub("SrcReg2", code)
398        immCode = matcher.sub("imm8", code)
399
400        class RegOpChild(RegOp):
401            mnemonic = name
402            className = Name
403            def __init__(self, src1, src2, flags=None, dataSize="env.dataSize"):
404                super(RegOpChild, self).__init__("NUM_INTREGS", src1, src2, flags, dataSize)
405
406        microopClasses[name] = RegOpChild
407
408        setUpMicroRegOp(name, Name, "X86ISA::RegOp", regCode, "", "true", elseCode);
409        setUpMicroRegOp(name, Name + "Flags", "X86ISA::RegOp", regCode, "", checkCCFlagBits, elseCode);
410
411        class RegOpChildImm(RegOpImm):
412            mnemonic = name + 'i'
413            className = Name + 'Imm'
414            def __init__(self, src1, src2, flags=None, dataSize="env.dataSize"):
415                super(RegOpChildImm, self).__init__("NUM_INTREGS", src1, src2, flags, dataSize)
416
417        microopClasses[name + 'i'] = RegOpChildImm
418
419        setUpMicroRegOp(name + 'i', Name + "Imm", "X86ISA::RegOpImm", immCode, "", "true", elseCode);
420        setUpMicroRegOp(name + 'i', Name + "ImmFlags", "X86ISA::RegOpImm", immCode, "", checkCCFlagBits, elseCode);
421
422    defineMicroRegOpWr('Wrip', 'RIP = SrcReg1 + op2', elseCode="RIP = RIP;")
423
424    # This has it's own function because Rd ops don't always have two parameters
425    def defineMicroRegOpRd(mnemonic, code):
426        Name = mnemonic
427        name = mnemonic.lower()
428
429        class RegOpChild(RegOp):
430            def __init__(self, dest, src1 = "NUM_INTREGS", dataSize="env.dataSize"):
431                super(RegOpChild, self).__init__(dest, src1, "NUM_INTREGS", None, dataSize)
432                self.className = Name
433                self.mnemonic = name
434
435        microopClasses[name] = RegOpChild
436
437        setUpMicroRegOp(name, Name, "X86ISA::RegOp", code, "", "true", ";");
438
439    defineMicroRegOpRd('Rdip', 'DestReg = RIP')
440
441    def defineMicroRegOpImm(mnemonic, code):
442        Name = mnemonic
443        name = mnemonic.lower()
444
445        class RegOpChild(RegOpImm):
446            def __init__(self, dest, src1, src2, dataSize="env.dataSize"):
447                super(RegOpChild, self).__init__(dest, src1, src2, None, dataSize)
448                self.className = Name
449                self.mnemonic = name
450
451        microopClasses[name] = RegOpChild
452
453        setUpMicroRegOp(name, Name, "X86ISA::RegOpImm", code, "", "true", ";");
454
455    defineMicroRegOpImm('Sext', '''
456            IntReg val = SrcReg1;
457            int sign_bit = bits(val, imm8-1, imm8-1);
458            val = sign_bit ? (val | ~mask(imm8)) : val;
459            DestReg = merge(DestReg, val, dataSize);''')
460}};
461