regop.isa revision 4725:441c280b5936
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    defineMicroRegOp('Add', 'DestReg = merge(DestReg, SrcReg1 + op2, dataSize)')
385    defineMicroRegOp('Or', 'DestReg = merge(DestReg, SrcReg1 | op2, dataSize)')
386    defineMicroRegOp('Adc', 'DestReg = merge(DestReg, SrcReg1 + op2, dataSize)')
387    defineMicroRegOp('Sbb', 'DestReg = merge(DestReg, SrcReg1 - op2, dataSize)', True)
388    defineMicroRegOp('And', 'DestReg = merge(DestReg, SrcReg1 & op2, dataSize)')
389    defineMicroRegOp('Sub', 'DestReg = merge(DestReg, SrcReg1 - op2, dataSize)', True)
390    defineMicroRegOp('Xor', 'DestReg = merge(DestReg, SrcReg1 ^ op2, dataSize)')
391    defineMicroRegOp('Cmp', 'DestReg = merge(DestReg, DestReg - op2, dataSize)', True)
392    defineMicroRegOp('Mul1s', 'DestReg = merge(DestReg, DestReg * op2, dataSize)')
393    defineMicroRegOp('Mov', 'DestReg = merge(SrcReg1, op2, dataSize)',
394            elseCode='DestReg=DestReg;', cc=True)
395
396    # Shift instructions
397    defineMicroRegOp('Sll', '''
398            uint8_t shiftAmt = (op2 & ((dataSize == 8) ? mask(4) : mask(3)));
399            DestReg = merge(DestReg, SrcReg1 << shiftAmt, dataSize);
400            ''')
401    # There are special rules for the flag for a single bit shift
402    defineMicroRegOp('Bll', '''
403            DestReg = merge(DestReg, SrcReg1 << 1, dataSize);
404            ''')
405
406    # This has it's own function because Wr ops have implicit destinations
407    def defineMicroRegOpWr(mnemonic, code, elseCode=";"):
408        Name = mnemonic
409        name = mnemonic.lower()
410
411        # Find op2 in each of the instruction definitions. Create two versions
412        # of the code, one with an integer operand, and one with an immediate
413        # operand.
414        matcher = re.compile("op2(?P<typeQual>\\.\\w+)?")
415        regCode = matcher.sub("SrcReg2", code)
416        immCode = matcher.sub("imm8", code)
417
418        class RegOpChild(RegOp):
419            mnemonic = name
420            className = Name
421            def __init__(self, src1, src2, flags=None, dataSize="env.dataSize"):
422                super(RegOpChild, self).__init__("NUM_INTREGS", src1, src2, flags, dataSize)
423
424        microopClasses[name] = RegOpChild
425
426        setUpMicroRegOp(name, Name, "X86ISA::RegOp", regCode);
427        setUpMicroRegOp(name, Name + "Flags", "X86ISA::RegOp", regCode,
428                condCheck = checkCCFlagBits, elseCode = elseCode);
429
430        class RegOpChildImm(RegOpImm):
431            mnemonic = name + 'i'
432            className = Name + 'Imm'
433            def __init__(self, src1, src2, flags=None, dataSize="env.dataSize"):
434                super(RegOpChildImm, self).__init__("NUM_INTREGS", src1, src2, flags, dataSize)
435
436        microopClasses[name + 'i'] = RegOpChildImm
437
438        setUpMicroRegOp(name + 'i', Name + "Imm", "X86ISA::RegOpImm", immCode);
439        setUpMicroRegOp(name + 'i', Name + "ImmFlags", "X86ISA::RegOpImm", immCode,
440                condCheck = checkCCFlagBits, elseCode = elseCode);
441
442    defineMicroRegOpWr('Wrip', 'RIP = SrcReg1 + op2', elseCode="RIP = RIP;")
443
444    # This has it's own function because Rd ops don't always have two parameters
445    def defineMicroRegOpRd(mnemonic, code):
446        Name = mnemonic
447        name = mnemonic.lower()
448
449        class RegOpChild(RegOp):
450            def __init__(self, dest, src1 = "NUM_INTREGS", dataSize="env.dataSize"):
451                super(RegOpChild, self).__init__(dest, src1, "NUM_INTREGS", None, dataSize)
452                self.className = Name
453                self.mnemonic = name
454
455        microopClasses[name] = RegOpChild
456
457        setUpMicroRegOp(name, Name, "X86ISA::RegOp", code);
458
459    defineMicroRegOpRd('Rdip', 'DestReg = RIP')
460
461    def defineMicroRegOpImm(mnemonic, code):
462        Name = mnemonic
463        name = mnemonic.lower()
464
465        class RegOpChild(RegOpImm):
466            def __init__(self, dest, src1, src2, dataSize="env.dataSize"):
467                super(RegOpChild, self).__init__(dest, src1, src2, None, dataSize)
468                self.className = Name
469                self.mnemonic = name
470
471        microopClasses[name] = RegOpChild
472
473        setUpMicroRegOp(name, Name, "X86ISA::RegOpImm", code);
474
475    defineMicroRegOpImm('Sext', '''
476            IntReg val = SrcReg1;
477            int sign_bit = bits(val, imm8-1, imm8-1);
478            val = sign_bit ? (val | ~mask(imm8)) : val;
479            DestReg = merge(DestReg, val, dataSize);''')
480
481    defineMicroRegOpImm('Zext', 'DestReg = bits(SrcReg1, imm8-1, 0);')
482}};
483