// 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: Gabe Black
//          Steve Reinhardt

////////////////////////////////////////////////////////////////////
//
// Trap instructions
//

output header {{
        /**
         * Base class for trap instructions,
         * or instructions that always fault.
         */
        class Trap : public SparcStaticInst
        {
          protected:

            // Constructor
            Trap(const char *mnem, ExtMachInst _machInst, OpClass __opClass) :
                SparcStaticInst(mnem, _machInst, __opClass), trapNum(SW_TRAP)
            {
            }

            std::string generateDisassembly(Addr pc,
                    const SymbolTable *symtab) const;

            int trapNum;
        };
}};

output decoder {{
        std::string
        Trap::generateDisassembly(Addr pc, const SymbolTable *symtab) const
        {
            std::stringstream response;

            printMnemonic(response, mnemonic);
            ccprintf(response, " ");
            printReg(response, _srcRegIdx[0]);
            ccprintf(response, ", 0x%x", trapNum);
            ccprintf(response, ", or ");
            printReg(response, _srcRegIdx[1]);
            return response.str();
        }
}};

def template TrapExecute {{
        Fault
        %(class_name)s::execute(%(CPU_exec_context)s *xc,
                Trace::InstRecord *traceData) const
        {
            Fault fault = NoFault;
            %(op_decl)s;
            %(op_rd)s;
            %(code)s
            return fault;
        }
}};

def template FpUnimplExecute {{
        Fault
        %(class_name)s::execute(%(CPU_exec_context)s *xc,
                Trace::InstRecord *traceData) const
        {
            Fault fault = NoFault;
            %(op_decl)s;
            %(op_rd)s;
            %(code)s
            %(op_wb)s;
            return fault;
        }
}};

def format Trap(code, *opt_flags) {{
        iop = InstObjParams(name, Name, 'Trap', code, opt_flags)
        header_output = BasicDeclare.subst(iop)
        decoder_output = BasicConstructor.subst(iop)
        decode_block = BasicDecode.subst(iop)
        exec_output = TrapExecute.subst(iop)
}};

output header {{
        class FpUnimpl : public SparcStaticInst
        {
          protected:
            FpUnimpl(const char *mnem,
                    ExtMachInst _machInst, OpClass __opClass)
                : SparcStaticInst(mnem, _machInst, __opClass)
            {
            }

            std::string
            generateDisassembly(Addr pc,  const SymbolTable *symtab) const
            {
                return mnemonic;
            }
        };
}};

def format FpUnimpl(*flags) {{
        fpunimpl_code = '''
            Fsr = insertBits(Fsr, 16, 14, 3);
            fault = new FpExceptionOther;
            '''
        iop = InstObjParams(name, Name, 'FpUnimpl', fpunimpl_code, flags)
        header_output = BasicDeclare.subst(iop)
        decoder_output = BasicConstructor.subst(iop)
        decode_block = BasicDecode.subst(iop)
        exec_output = FpUnimplExecute.subst(iop)
}};
