fpop.isa revision 5083
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// FpOp Microop templates
59//
60//////////////////////////////////////////////////////////////////////////
61
62def template MicroFpOpExecute {{
63        Fault %(class_name)s::execute(%(CPU_exec_context)s *xc,
64                Trace::InstRecord *traceData) const
65        {
66            Fault fault = NoFault;
67
68            DPRINTF(X86, "The data size is %d\n", dataSize);
69            %(op_decl)s;
70            %(op_rd)s;
71
72            if(%(cond_check)s)
73            {
74                %(code)s;
75                %(flag_code)s;
76                %(top_code)s;
77            }
78            else
79            {
80                %(else_code)s;
81            }
82
83            //Write the resulting state to the execution context
84            if(fault == NoFault)
85            {
86                %(op_wb)s;
87            }
88            return fault;
89        }
90}};
91
92def template MicroFpOpDeclare {{
93    class %(class_name)s : public %(base_class)s
94    {
95      protected:
96        void buildMe();
97
98      public:
99        %(class_name)s(ExtMachInst _machInst,
100                const char * instMnem,
101                bool isMicro, bool isDelayed, bool isFirst, bool isLast,
102                RegIndex _src1, RegIndex _src2, RegIndex _dest,
103                uint8_t _dataSize, int8_t _spm);
104
105        %(class_name)s(ExtMachInst _machInst,
106                const char * instMnem,
107                RegIndex _src1, RegIndex _src2, RegIndex _dest,
108                uint8_t _dataSize, int8_t _spm);
109
110        %(BasicExecDeclare)s
111    };
112}};
113
114def template MicroFpOpConstructor {{
115
116    inline void %(class_name)s::buildMe()
117    {
118        %(constructor)s;
119    }
120
121    inline %(class_name)s::%(class_name)s(
122            ExtMachInst machInst, const char * instMnem,
123            RegIndex _src1, RegIndex _src2, RegIndex _dest,
124            uint8_t _dataSize, int8_t _spm) :
125        %(base_class)s(machInst, "%(mnemonic)s", instMnem,
126                false, false, false, false,
127                _src1, _src2, _dest, _dataSize, _spm,
128                %(op_class)s)
129    {
130        buildMe();
131    }
132
133    inline %(class_name)s::%(class_name)s(
134            ExtMachInst machInst, const char * instMnem,
135            bool isMicro, bool isDelayed, bool isFirst, bool isLast,
136            RegIndex _src1, RegIndex _src2, RegIndex _dest,
137            uint8_t _dataSize, int8_t _spm) :
138        %(base_class)s(machInst, "%(mnemonic)s", instMnem,
139                isMicro, isDelayed, isFirst, isLast,
140                _src1, _src2, _dest, _dataSize, _spm,
141                %(op_class)s)
142    {
143        buildMe();
144    }
145}};
146
147let {{
148    # Make these empty strings so that concatenating onto
149    # them will always work.
150    header_output = ""
151    decoder_output = ""
152    exec_output = ""
153
154    class FpOpMeta(type):
155        def buildCppClasses(self, name, Name, suffix, \
156                code, flag_code, cond_check, else_code):
157
158            # Globals to stick the output in
159            global header_output
160            global decoder_output
161            global exec_output
162
163            # Stick all the code together so it can be searched at once
164            allCode = "|".join((code, flag_code, cond_check, else_code))
165
166            # If there's something optional to do with flags, generate
167            # a version without it and fix up this version to use it.
168            if flag_code is not "" or cond_check is not "true":
169                self.buildCppClasses(name, Name, suffix,
170                        code, "", "true", else_code)
171                suffix = "Flags" + suffix
172
173            base = "X86ISA::FpOp"
174
175            # Get everything ready for the substitution
176            iop_top = InstObjParams(name, Name + suffix + "Top", base,
177                    {"code" : code,
178                     "flag_code" : flag_code,
179                     "cond_check" : cond_check,
180                     "else_code" : else_code,
181                     "top_code" : "TOP = (TOP + spm + 8) % 8;"})
182            iop = InstObjParams(name, Name + suffix, base,
183                    {"code" : code,
184                     "flag_code" : flag_code,
185                     "cond_check" : cond_check,
186                     "else_code" : else_code,
187                     "top_code" : ";"})
188
189            # Generate the actual code (finally!)
190            header_output += MicroFpOpDeclare.subst(iop_top)
191            decoder_output += MicroFpOpConstructor.subst(iop_top)
192            exec_output += MicroFpOpExecute.subst(iop_top)
193            header_output += MicroFpOpDeclare.subst(iop)
194            decoder_output += MicroFpOpConstructor.subst(iop)
195            exec_output += MicroFpOpExecute.subst(iop)
196
197
198        def __new__(mcls, Name, bases, dict):
199            abstract = False
200            name = Name.lower()
201            if "abstract" in dict:
202                abstract = dict['abstract']
203                del dict['abstract']
204
205            cls = super(FpOpMeta, mcls).__new__(mcls, Name, bases, dict)
206            if not abstract:
207                cls.className = Name
208                cls.mnemonic = name
209                code = cls.code
210                flag_code = cls.flag_code
211                cond_check = cls.cond_check
212                else_code = cls.else_code
213
214                # Set up the C++ classes
215                mcls.buildCppClasses(cls, name, Name, "",
216                        code, flag_code, cond_check, else_code)
217
218                # Hook into the microassembler dict
219                global microopClasses
220                microopClasses[name] = cls
221
222            return cls
223
224
225    class FpOp(X86Microop):
226        __metaclass__ = FpOpMeta
227        # This class itself doesn't act as a microop
228        abstract = True
229
230        # Default template parameter values
231        flag_code = ""
232        cond_check = "true"
233        else_code = ";"
234
235        def __init__(self, dest, src1, src2, spm=0, \
236                SetStatus=False, dataSize="env.dataSize"):
237            self.dest = dest
238            self.src1 = src1
239            self.src2 = src2
240            self.spm = spm
241            self.dataSize = dataSize
242            if SetStatus:
243                self.className += "Flags"
244            if spm:
245                self.className += "Top"
246
247        def getAllocator(self, *microFlags):
248            return '''new %(class_name)s(machInst, mnemonic
249                    %(flags)s, %(src1)s, %(src2)s, %(dest)s,
250                    %(dataSize)s, %(spm)d)''' % {
251                "class_name" : self.className,
252                "flags" : self.microFlagsText(microFlags),
253                "src1" : self.src1, "src2" : self.src2,
254                "dest" : self.dest,
255                "dataSize" : self.dataSize,
256                "spm" : self.spm}
257
258    class Movfp(FpOp):
259        def __init__(self, dest, src1, flags=0, spm=0, \
260                SetStatus=False, dataSize="env.dataSize"):
261            super(Movfp, self).__init__(dest, src1, flags, \
262                    spm, SetStatus, dataSize)
263        code = 'FpDestReg.uqw = FpSrcReg2.uqw;'
264        else_code = 'FpDestReg.uqw = FpDestReg.uqw;'
265        cond_check = "checkCondition(ccFlagBits, src2)"
266
267    class Xorfp(FpOp):
268        code = 'FpDestReg.uqw = FpSrcReg1.uqw ^ FpSrcReg2.uqw;'
269
270    class Sqrtfp(FpOp):
271        code = 'FpDestReg = sqrt(FpSrcReg2);'
272
273    # Conversion microops
274    class ConvOp(FpOp):
275        abstract = True
276        def __init__(self, dest, src1):
277            super(ConvOp, self).__init__(dest, src1, "(int)FLOATREG_MICROFP0")
278
279    # These probably shouldn't look at the ExtMachInst directly to figure
280    # out what size to use and should instead delegate that to the macroop's
281    # constructor. That would be more efficient, and it would make the
282    # microops a little more modular.
283    class cvtf_i2d(ConvOp):
284        code = '''
285            X86IntReg intReg = SSrcReg1;
286            if (REX_W)
287                FpDestReg = intReg.SR;
288            else
289                FpDestReg = intReg.SE;
290            '''
291
292    class cvtf_i2d_hi(ConvOp):
293        code = 'FpDestReg = bits(SSrcReg1, 63, 32);'
294
295    class cvtf_d2i(ConvOp):
296        code = '''
297            int64_t intSrcReg1 = static_cast<int64_t>(FpSrcReg1);
298            if (REX_W)
299                SDestReg = intSrcReg1;
300            else
301                SDestReg = merge(SDestReg, intSrcReg1, 4);
302            '''
303
304    # These need to consider size at some point. They'll always use doubles
305    # for the moment.
306    class addfp(FpOp):
307        code = 'FpDestReg = FpSrcReg1 + FpSrcReg2;'
308
309    class mulfp(FpOp):
310        code = 'FpDestReg = FpSrcReg1 * FpSrcReg2;'
311
312    class divfp(FpOp):
313        code = 'FpDestReg = FpSrcReg1 / FpSrcReg2;'
314
315    class subfp(FpOp):
316        code = 'FpDestReg = FpSrcReg1 - FpSrcReg2;'
317
318    class Compfp(FpOp):
319        def __init__(self, src1, src2, spm=0, setStatus=False, \
320                dataSize="env.dataSize"):
321            super(Compfp, self).__init__("(int)FLOATREG_MICROFP0", \
322                    src1, src2, spm, setStatus, dataSize)
323        # This class sets the condition codes in rflags according to the
324        # rules for comparing floating point.
325        code = '''
326            //               ZF PF CF
327            // Unordered      1  1  1
328            // Greater than   0  0  0
329            // Less than      0  0  1
330            // Equal          1  0  0
331            //           OF = SF = AF = 0
332            ccFlagBits = ccFlagBits & ~(OFBit | SFBit | AFBit |
333                                        ZFBit | PFBit | CFBit);
334            if (isnan(FpSrcReg1) || isnan(FpSrcReg2))
335                ccFlagBits = ccFlagBits | (ZFBit | PFBit | CFBit);
336            else if(FpSrcReg1 < FpSrcReg2)
337                ccFlagBits = ccFlagBits | CFBit;
338            else if(FpSrcReg1 == FpSrcReg2)
339                ccFlagBits = ccFlagBits | ZFBit;
340        '''
341}};
342