fpop.isa revision 6345
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                InstRegIndex _src1, InstRegIndex _src2, InstRegIndex _dest,
103                uint8_t _dataSize, int8_t _spm);
104
105        %(class_name)s(ExtMachInst _machInst,
106                const char * instMnem,
107                InstRegIndex _src1, InstRegIndex _src2, InstRegIndex _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            InstRegIndex _src1, InstRegIndex _src2, InstRegIndex _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            InstRegIndex _src1, InstRegIndex _src2, InstRegIndex _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, macrocodeBlock
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, spm=0, \
260                SetStatus=False, dataSize="env.dataSize"):
261            super(Movfp, self).__init__(dest, src1, "InstRegIndex(0)", \
262                    spm, SetStatus, dataSize)
263        code = 'FpDestReg.uqw = FpSrcReg1.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, \
278                    "InstRegIndex(FLOATREG_MICROFP0)")
279
280    # These probably shouldn't look at the ExtMachInst directly to figure
281    # out what size to use and should instead delegate that to the macroop's
282    # constructor. That would be more efficient, and it would make the
283    # microops a little more modular.
284    class cvtf_i2d(ConvOp):
285        code = '''
286            X86IntReg intReg = SSrcReg1;
287            if (REX_W)
288                FpDestReg = intReg.SR;
289            else
290                FpDestReg = intReg.SE;
291            '''
292
293    class cvtf_i2d_hi(ConvOp):
294        code = 'FpDestReg = bits(SSrcReg1, 63, 32);'
295
296    class cvtf_d2i(ConvOp):
297        code = '''
298            int64_t intSrcReg1 = static_cast<int64_t>(FpSrcReg1);
299            if (REX_W)
300                SDestReg = intSrcReg1;
301            else
302                SDestReg = merge(SDestReg, intSrcReg1, 4);
303            '''
304
305    # These need to consider size at some point. They'll always use doubles
306    # for the moment.
307    class addfp(FpOp):
308        code = 'FpDestReg = FpSrcReg1 + FpSrcReg2;'
309
310    class mulfp(FpOp):
311        code = 'FpDestReg = FpSrcReg1 * FpSrcReg2;'
312
313    class divfp(FpOp):
314        code = 'FpDestReg = FpSrcReg1 / FpSrcReg2;'
315
316    class subfp(FpOp):
317        code = 'FpDestReg = FpSrcReg1 - FpSrcReg2;'
318
319    class Compfp(FpOp):
320        def __init__(self, src1, src2, spm=0, setStatus=False, \
321                dataSize="env.dataSize"):
322            super(Compfp, self).__init__("InstRegIndex(FLOATREG_MICROFP0)", \
323                    src1, src2, spm, setStatus, dataSize)
324        # This class sets the condition codes in rflags according to the
325        # rules for comparing floating point.
326        code = '''
327            //               ZF PF CF
328            // Unordered      1  1  1
329            // Greater than   0  0  0
330            // Less than      0  0  1
331            // Equal          1  0  0
332            //           OF = SF = AF = 0
333            ccFlagBits = ccFlagBits & ~(OFBit | SFBit | AFBit |
334                                        ZFBit | PFBit | CFBit);
335            if (isnan(FpSrcReg1) || isnan(FpSrcReg2))
336                ccFlagBits = ccFlagBits | (ZFBit | PFBit | CFBit);
337            else if(FpSrcReg1 < FpSrcReg2)
338                ccFlagBits = ccFlagBits | CFBit;
339            else if(FpSrcReg1 == FpSrcReg2)
340                ccFlagBits = ccFlagBits | ZFBit;
341        '''
342}};
343