fp.isa revision 9999:fdd2d34b0871
1// -*- mode:c++ -*-
2
3// Copyright (c) 2007 MIPS Technologies, Inc.
4// All rights reserved.
5//
6// Redistribution and use in source and binary forms, with or without
7// modification, are permitted provided that the following conditions are
8// met: redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer;
10// redistributions in binary form must reproduce the above copyright
11// notice, this list of conditions and the following disclaimer in the
12// documentation and/or other materials provided with the distribution;
13// neither the name of the copyright holders nor the names of its
14// contributors may be used to endorse or promote products derived from
15// this software without specific prior written permission.
16//
17// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28//
29// Authors: Korey Sewell
30
31////////////////////////////////////////////////////////////////////
32//
33// Floating Point operate instructions
34//
35
36output header {{
37        /**
38         * Base class for FP operations.
39         */
40        class FPOp : public MipsStaticInst
41        {
42                protected:
43
44                /// Constructor
45                FPOp(const char *mnem, MachInst _machInst, OpClass __opClass) : MipsStaticInst(mnem, _machInst, __opClass)
46                {
47                }
48
49            //std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
50
51                //needs function to check for fpEnable or not
52        };
53
54        class FPCompareOp : public FPOp
55        {
56          protected:
57            FPCompareOp(const char *mnem, MachInst _machInst, OpClass __opClass) : FPOp(mnem, _machInst, __opClass)
58                {
59                }
60
61            std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
62
63        };
64}};
65
66output decoder {{
67        std::string FPCompareOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const
68        {
69            std::stringstream ss;
70
71            ccprintf(ss, "%-10s ", mnemonic);
72
73            ccprintf(ss,"%d",CC);
74
75            if(_numSrcRegs > 0) {
76                ss << ", ";
77                printReg(ss, _srcRegIdx[0]);
78            }
79
80            if(_numSrcRegs > 1) {
81                ss << ", ";
82                printReg(ss, _srcRegIdx[1]);
83            }
84
85            return ss.str();
86        }
87}};
88
89output header {{
90        void fpResetCauseBits(%(CPU_exec_context)s *cpu);
91
92}};
93
94output exec {{
95        inline Fault checkFpEnableFault(%(CPU_exec_context)s *xc)
96        {
97            //@TODO: Implement correct CP0 checks to see if the CP1
98            // unit is enable or not
99          if (!isCoprocessorEnabled(xc, 1))
100             return new CoprocessorUnusableFault(1);
101
102          return NoFault;
103        }
104
105        //If any operand is Nan return the appropriate QNaN
106        template <class T>
107        bool
108        fpNanOperands(FPOp *inst, %(CPU_exec_context)s *xc, const T &src_type,
109                      Trace::InstRecord *traceData)
110        {
111            uint64_t mips_nan = 0;
112            assert(sizeof(T) == 4);
113
114            for (int i = 0; i < inst->numSrcRegs(); i++) {
115                uint64_t src_bits = xc->readFloatRegOperandBits(inst, 0);
116
117                if (isNan(&src_bits, 32) ) {
118                    mips_nan = MIPS32_QNAN;
119                    xc->setFloatRegOperandBits(inst, 0, mips_nan);
120                    if (traceData) { traceData->setData(mips_nan); }
121                    return true;
122                }
123            }
124            return false;
125        }
126
127        template <class T>
128        bool
129        fpInvalidOp(FPOp *inst, %(CPU_exec_context)s *cpu, const T dest_val,
130                    Trace::InstRecord *traceData)
131        {
132            uint64_t mips_nan = 0;
133            T src_op = dest_val;
134            assert(sizeof(T) == 4);
135
136            if (isNan(&src_op, 32)) {
137                mips_nan = MIPS32_QNAN;
138
139                //Set value to QNAN
140                cpu->setFloatRegOperandBits(inst, 0, mips_nan);
141
142                //Read FCSR from FloatRegFile
143                uint32_t fcsr_bits =
144                    cpu->tcBase()->readFloatRegBits(FLOATREG_FCSR);
145
146                uint32_t new_fcsr = genInvalidVector(fcsr_bits);
147
148                //Write FCSR from FloatRegFile
149                cpu->tcBase()->setFloatRegBits(FLOATREG_FCSR, new_fcsr);
150
151                if (traceData) { traceData->setData(mips_nan); }
152                return true;
153            }
154
155            return false;
156        }
157
158        void
159        fpResetCauseBits(%(CPU_exec_context)s *cpu)
160        {
161            //Read FCSR from FloatRegFile
162            uint32_t fcsr = cpu->tcBase()->readFloatRegBits(FLOATREG_FCSR);
163
164            // TODO: Use utility function here
165            fcsr = bits(fcsr, 31, 18) << 18 | bits(fcsr, 11, 0);
166
167            //Write FCSR from FloatRegFile
168            cpu->tcBase()->setFloatRegBits(FLOATREG_FCSR, fcsr);
169        }
170}};
171
172def template FloatingPointExecute {{
173        Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, Trace::InstRecord *traceData) const
174        {
175                Fault fault = NoFault;
176
177                %(fp_enable_check)s;
178
179
180                //When is the right time to reset cause bits?
181                //start of every instruction or every cycle?
182                if (FullSystem)
183                    fpResetCauseBits(xc);
184                %(op_decl)s;
185                %(op_rd)s;
186
187                //Check if any FP operand is a NaN value
188                if (!fpNanOperands((FPOp*)this, xc, Fd, traceData)) {
189                    %(code)s;
190
191                    //Change this code for Full-System/Sycall Emulation
192                    //separation
193                    //----
194                    //Should Full System-Mode throw a fault here?
195                    //----
196                    //Check for IEEE 754 FP Exceptions
197                    //fault = fpNanOperands((FPOp*)this, xc, Fd, traceData);
198                    bool invalid_op = false;
199                    if (FullSystem) {
200                        invalid_op =
201                            fpInvalidOp((FPOp*)this, xc, Fd, traceData);
202                    }
203                    if (!invalid_op && fault == NoFault) {
204                        %(op_wb)s;
205                    }
206                }
207
208                return fault;
209        }
210}};
211
212// Primary format for float point operate instructions:
213def format FloatOp(code, *flags) {{
214        iop = InstObjParams(name, Name, 'FPOp', code, flags)
215        header_output = BasicDeclare.subst(iop)
216        decoder_output = BasicConstructor.subst(iop)
217        decode_block = BasicDecode.subst(iop)
218        exec_output = FloatingPointExecute.subst(iop)
219}};
220
221def format FloatCompareOp(cond_code, *flags) {{
222    import sys
223
224    code = 'bool cond;\n'
225    if '_sf' in cond_code or 'SinglePrecision' in flags:
226        if 'QnanException' in flags:
227            code += 'if (isQnan(&Fs_sf, 32) || isQnan(&Ft_sf, 32)) {\n'
228            code += '\tFCSR = genInvalidVector(FCSR);\n'
229            code += '\treturn NoFault;'
230            code += '}\n else '
231        code += 'if (isNan(&Fs_sf, 32) || isNan(&Ft_sf, 32)) {\n'
232    elif '_df' in cond_code or 'DoublePrecision' in flags:
233        if 'QnanException' in flags:
234            code += 'if (isQnan(&Fs_df, 64) || isQnan(&Ft_df, 64)) {\n'
235            code += '\tFCSR = genInvalidVector(FCSR);\n'
236            code += '\treturn NoFault;'
237            code += '}\n else '
238        code += 'if (isNan(&Fs_df, 64) || isNan(&Ft_df, 64)) {\n'
239    else:
240       sys.exit('Decoder Failed: Can\'t Determine Operand Type\n')
241
242    if 'UnorderedTrue' in flags:
243       code += 'cond = 1;\n'
244    elif 'UnorderedFalse' in flags:
245       code += 'cond = 0;\n'
246    else:
247       sys.exit('Decoder Failed: Float Compare Instruction Needs A Unordered Flag\n')
248
249    code += '} else {\n'
250    code +=  cond_code + '}'
251    code += 'FCSR = genCCVector(FCSR, CC, cond);\n'
252
253    iop = InstObjParams(name, Name, 'FPCompareOp', code)
254    header_output = BasicDeclare.subst(iop)
255    decoder_output = BasicConstructor.subst(iop)
256    decode_block = BasicDecode.subst(iop)
257    exec_output = BasicExecute.subst(iop)
258}};
259
260def format FloatConvertOp(code, *flags) {{
261    import sys
262
263    #Determine Source Type
264    convert = 'fpConvert('
265    if '_sf' in code:
266        code = 'float ' + code + '\n'
267        convert += 'SINGLE_TO_'
268    elif '_df' in code:
269        code = 'double ' + code + '\n'
270        convert += 'DOUBLE_TO_'
271    elif '_sw' in code:
272        code = 'int32_t ' + code + '\n'
273        convert += 'WORD_TO_'
274    elif '_sd' in code:
275        code = 'int64_t ' + code + '\n'
276        convert += 'LONG_TO_'
277    else:
278        sys.exit("Error Determining Source Type for Conversion")
279
280    #Determine Destination Type
281    if 'ToSingle' in flags:
282        code += 'Fd_uw = ' + convert + 'SINGLE, '
283    elif 'ToDouble' in flags:
284        code += 'Fd_ud = ' + convert + 'DOUBLE, '
285    elif 'ToWord' in flags:
286        code += 'Fd_uw = ' + convert + 'WORD, '
287    elif 'ToLong' in flags:
288        code += 'Fd_ud = ' + convert + 'LONG, '
289    else:
290        sys.exit("Error Determining Destination Type for Conversion")
291
292    #Figure out how to round value
293    if 'Ceil' in flags:
294        code += 'ceil(val)); '
295    elif 'Floor' in flags:
296        code += 'floor(val)); '
297    elif 'Round' in flags:
298        code += 'roundFP(val, 0)); '
299    elif 'Trunc' in flags:
300        code += 'truncFP(val));'
301    else:
302        code += 'val); '
303
304    iop = InstObjParams(name, Name, 'FPOp', code)
305    header_output = BasicDeclare.subst(iop)
306    decoder_output = BasicConstructor.subst(iop)
307    decode_block = BasicDecode.subst(iop)
308    exec_output = BasicExecute.subst(iop)
309}};
310
311def format FloatAccOp(code, *flags) {{
312        iop = InstObjParams(name, Name, 'FPOp', code, flags)
313        header_output = BasicDeclare.subst(iop)
314        decoder_output = BasicConstructor.subst(iop)
315        decode_block = BasicDecode.subst(iop)
316        exec_output = BasicExecute.subst(iop)
317}};
318
319// Primary format for float64 operate instructions:
320def format Float64Op(code, *flags) {{
321        iop = InstObjParams(name, Name, 'MipsStaticInst', code, flags)
322        header_output = BasicDeclare.subst(iop)
323        decoder_output = BasicConstructor.subst(iop)
324        decode_block = BasicDecode.subst(iop)
325        exec_output = BasicExecute.subst(iop)
326}};
327
328def format FloatPSCompareOp(cond_code1, cond_code2, *flags) {{
329    import sys
330
331    code = 'bool cond1, cond2;\n'
332    code += 'bool code_block1, code_block2;\n'
333    code += 'code_block1 = code_block2 = true;\n'
334
335    if 'QnanException' in flags:
336        code += 'if (isQnan(&Fs1_sf, 32) || isQnan(&Ft1_sf, 32)) {\n'
337        code += '\tFCSR = genInvalidVector(FCSR);\n'
338        code += 'code_block1 = false;'
339        code += '}\n'
340        code += 'if (isQnan(&Fs2_sf, 32) || isQnan(&Ft2_sf, 32)) {\n'
341        code += '\tFCSR = genInvalidVector(FCSR);\n'
342        code += 'code_block2 = false;'
343        code += '}\n'
344
345    code += 'if (code_block1) {'
346    code += '\tif (isNan(&Fs1_sf, 32) || isNan(&Ft1_sf, 32)) {\n'
347    if 'UnorderedTrue' in flags:
348       code += 'cond1 = 1;\n'
349    elif 'UnorderedFalse' in flags:
350       code += 'cond1 = 0;\n'
351    else:
352       sys.exit('Decoder Failed: Float Compare Instruction Needs A Unordered Flag\n')
353    code += '} else {\n'
354    code +=  cond_code1
355    code += 'FCSR = genCCVector(FCSR, CC, cond1);}\n}\n'
356
357    code += 'if (code_block2) {'
358    code += '\tif (isNan(&Fs2_sf, 32) || isNan(&Ft2_sf, 32)) {\n'
359    if 'UnorderedTrue' in flags:
360       code += 'cond2 = 1;\n'
361    elif 'UnorderedFalse' in flags:
362       code += 'cond2 = 0;\n'
363    else:
364       sys.exit('Decoder Failed: Float Compare Instruction Needs A Unordered Flag\n')
365    code += '} else {\n'
366    code +=  cond_code2
367    code += 'FCSR = genCCVector(FCSR, CC, cond2);}\n}'
368
369    iop = InstObjParams(name, Name, 'FPCompareOp', code)
370    header_output = BasicDeclare.subst(iop)
371    decoder_output = BasicConstructor.subst(iop)
372    decode_block = BasicDecode.subst(iop)
373    exec_output = BasicExecute.subst(iop)
374}};
375
376