// Copyright (c) 2006-2007 The Regents of The University of Michigan
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met: redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer;
// redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution;
// neither the name of the copyright holders nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Authors: Ali Saidi
//          Gabe Black
//          Steve Reinhardt

def template ROrImmDecode {{
    {
        return (I ? (SparcStaticInst *)(new %(class_name)sImm(machInst))
                  : (SparcStaticInst *)(new %(class_name)s(machInst)));
    }
}};

output header {{
    union DoubleSingle
    {
        double d;
        uint64_t ui;
        uint32_t s[2];
        DoubleSingle(double _d) : d(_d)
        {}
        DoubleSingle(uint64_t _ui) : ui(_ui)
        {}
        DoubleSingle(uint32_t _s0, uint32_t _s1)
        {
            s[0] = _s0;
            s[1] = _s1;
        }
    };
}};

let {{
    def filterDoubles(code):
        assignRE = re.compile(r'\s*=(?!=)', re.MULTILINE)
        for opName in ("Frd", "Frs1", "Frs2", "Frd_N"):
            next_pos = 0
            operandsREString = (r'''
            (?<!\w)             # neg. lookbehind assertion: prevent partial matches
            ((%s)(?:_([^\W_]+))?)   # match: operand with optional '.' then suffix
            (?!\w)             # neg. lookahead assertion: prevent partial matches
            ''' % opName)
            operandsRE = re.compile(operandsREString, re.MULTILINE|re.VERBOSE)
            is_src = False
            is_dest = False
            extension = None
            foundOne = False
            while 1:
                match = operandsRE.search(code, next_pos)
                if not match:
                    break
                foundOne = True
                op = match.groups()
                (op_full, op_base, op_ext) = op
                is_dest_local = (assignRE.match(code, match.end()) != None)
                is_dest = is_dest or is_dest_local
                is_src = is_src or not is_dest_local
                if extension and extension != op_ext:
                    raise Exception, "Inconsistent extensions in double filter."
                extension = op_ext
                next_pos = match.end()
            if foundOne:
                # Get rid of any unwanted extension
                code = operandsRE.sub(op_base, code)
                is_int = False
                member = "d"
                if extension in ("sb", "ub", "shw", "uhw", "sw", "uw", "sdw", "udw"):
                    is_int = True
                    member = "ui"
                if is_src:
                    code = ("%s = DoubleSingle(%s_high, %s_low).%s;" % \
                        (opName, opName, opName, member)) + code
                if is_dest:
                    code += '''
                        %s_low = DoubleSingle(%s).s[1];
                        %s_high = DoubleSingle(%s).s[0];''' % \
                             (opName, opName, opName, opName)
                if is_int:
                    code = ("uint64_t %s;" % opName) + code
                else:
                    code = ("double %s;" % opName) + code
        return code
}};

let {{
    def splitOutImm(code):
        matcher = re.compile(r'Rs(?P<rNum>\d)_or_imm(?P<iNum>\d+)(?P<typeQual>_[^\W_]+)?')
        rOrImmMatch = matcher.search(code)
        if (rOrImmMatch == None):
            return (False, code, '', '', '')
        rString = rOrImmMatch.group("rNum")
        if (rOrImmMatch.group("typeQual") != None):
            rString += rOrImmMatch.group("typeQual")
        iString = rOrImmMatch.group("iNum")
        orig_code = code
        code = matcher.sub('Rs' + rString, orig_code)
        imm_code = matcher.sub('imm', orig_code)
        return (True, code, imm_code, rString, iString)
}};

output exec {{
    /// Check "FP enabled" machine status bit.  Called when executing any FP
    /// instruction.
    /// @retval Full-system mode: NoFault if FP is enabled, FpDisabled
    /// if not.  Non-full-system mode: always returns NoFault.
    static inline Fault
    checkFpEnableFault(ExecContext *xc)
    {
        if (FullSystem) {
            PSTATE pstate = xc->readMiscReg(MISCREG_PSTATE);
            if (pstate.pef && xc->readMiscReg(MISCREG_FPRS) & 0x4) {
                return NoFault;
            } else {
                return std::make_shared<FpDisabled>();
            }
        } else {
            return NoFault;
        }
    }

    static inline Fault
    checkVecEnableFault(ExecContext *xc)
    {
        return std::make_shared<VecDisabled>();
    }
}};