/*
 * Copyright (c) 2003-2005 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.
 */

#ifndef __ARCH_SPARC_ISA_TRAITS_HH__
#define __ARCH_SPARC_ISA_TRAITS_HH__

#include "arch/sparc/faults.hh"
#include "base/misc.hh"
#include "config/full_system.hh"
#include "sim/host.hh"

//This makes sure the big endian versions of certain functions are used.
namespace BigEndianGuest {}
using namespace BigEndianGuest;

class ExecContext;
class FastCPU;
//class FullCPU;
class Checkpoint;

#define TARGET_SPARC

class StaticInst;
class StaticInstPtr;

//namespace EV5
//{
//	int DTB_ASN_ASN(uint64_t reg);
//	int ITB_ASN_ASN(uint64_t reg);
//}

namespace SparcISA
{
    typedef uint32_t MachInst;
    typedef uint64_t ExtMachInst;
    typedef uint8_t  RegIndex;

    const int NumFloatRegs = 32;
    const int NumMiscRegs = 32;

    const int MaxRegsOfAnyType = 32;
    const int // Static instruction parameters
    const int MaxInstSrcRegs = 3;
    const int MaxInstDestRegs = 2;

    const int // Maximum trap level
    const int MaxTL = 4;
    const int
    const int // semantically meaningful register indices
    const int ZeroReg = 0;	// architecturally meaningful
    const int // the rest of these depend on the ABI
    const int StackPointerReg = 14;
    const int ReturnAddressReg = 31;
    const int ReturnValueReg = 24;
    const int FramePointerReg = 30;
    const int ArgumentReg0 = 24;
    const int ArgumentReg1 = 25;
    const int ArgumentReg2 = 26;
    const int ArgumentReg3 = 27;
    const int ArgumentReg4 = 28;
    const int ArgumentReg5 = 29;
    const int
    const int //8K. This value is implmentation specific; and should probably
    const int //be somewhere else.
    const int LogVMPageSize = 13;
    const int VMPageSize = (1 << LogVMPageSize);

    typedef uint64_t IntReg;

    class IntRegFile
    {
        private:
          //For right now, let's pretend the register file is static
          IntReg regs[32];
        public:
          IntReg & operator [] (RegIndex index)
          {
              //Don't allow indexes outside of the 32 registers
              index &= 0x1F;
              return regs[index];
          }
    };

    void serialize(std::ostream & os);

    void unserialize(Checkpoint *cp, const std::string &section);

    typedef float float32_t;
    typedef double float64_t;
    //FIXME This actually usually refers to a 10 byte float, rather than a
    //16 byte float as required. This data type may have to be emulated.
    typedef long double float128_t;

    class FloatRegFile
    {
      private:
        //By using the largest data type, we ensure everything
        //is aligned correctly in memory
        union
        {
            float128_t rawRegs[16];
            uint64_t regDump[32];
        };
        class QuadRegs
        {
          private:
            FloatRegFile * parent;
          public:
            QuadRegs(FloatRegFile * p) : parent(p) {;}
            float128_t & operator [] (RegIndex index)
            {
                //Quad floats are index by the single
                //precision register the start on,
                //and only 16 should be accessed
                index = (index >> 2) & 0xF;
                return parent->rawRegs[index];
            }
        };
        class DoubleRegs
        {
          private:
            FloatRegFile * parent;
          public:
            DoubleRegs(FloatRegFile * p) : parent(p) {;}
            float64_t & operator [] (RegIndex index)
            {
                //Double floats are index by the single
                //precision register the start on,
                //and only 32 should be accessed
                index = (index >> 1) & 0x1F;
                return ((float64_t *)parent->rawRegs)[index];
            }
        };
        class SingleRegs
        {
          private:
            FloatRegFile * parent;
          public:
            SingleRegs(FloatRegFile * p) : parent(p) {;}
            float32_t & operator [] (RegIndex index)
            {
                //Only 32 single floats should be accessed
                index &= 0x1F;
                return ((float32_t *)parent->rawRegs)[index];
            }
        };
      public:
        void serialize(std::ostream & os);

        void unserialize(Checkpoint * cp, std::string & section);

        QuadRegs quadRegs;
        DoubleRegs doubleRegs;
        SingleRegs singleRegs;
        FloatRegFile() : quadRegs(this), doubleRegs(this), singleRegs(this)
        {;}
    };

    // control register file contents
    typedef uint64_t MiscReg;
    // The control registers, broken out into fields
    class MiscRegFile
    {
      private:
        union
        {
            uint16_t pstate;		// Process State Register
            struct
            {
                uint16_t ag:1;		// Alternate Globals
                uint16_t ie:1;		// Interrupt enable
                uint16_t priv:1;	// Privelege mode
                uint16_t am:1;		// Address mask
                uint16_t pef:1;		// PSTATE enable floating-point
                uint16_t red:1;		// RED (reset, error, debug) state
                uint16_t mm:2;		// Memory Model
                uint16_t tle:1;		// Trap little-endian
                uint16_t cle:1;		// Current little-endian
            } pstateFields;
        };
        uint64_t tba;		// Trap Base Address
        union
        {
            uint64_t y;		// Y (used in obsolete multiplication)
            struct
            {
                uint64_t value:32;	// The actual value stored in y
                uint64_t :32;	// reserved bits
            } yFields;
        };
        uint8_t pil;		// Process Interrupt Register
        uint8_t cwp;		// Current Window Pointer
        uint16_t tt[MaxTL];	// Trap Type (Type of trap which occured
                                // on the previous level)
        union
        {
            uint8_t	ccr;		// Condition Code Register
            struct
            {
                union
                {
                    uint8_t icc:4;	// 32-bit condition codes
                    struct
                    {
                        uint8_t c:1;	// Carry
                        uint8_t v:1;	// Overflow
                        uint8_t z:1;	// Zero
                        uint8_t n:1;	// Negative
                    } iccFields;
                };
                union
                {
                    uint8_t xcc:4;	// 64-bit condition codes
                    struct
                    {
                        uint8_t c:1;	// Carry
                        uint8_t v:1;	// Overflow
                        uint8_t z:1;	// Zero
                        uint8_t n:1;	// Negative
                    } xccFields;
                };
            } ccrFields;
        };
        uint8_t asi;		// Address Space Identifier
        uint8_t tl;		// Trap Level
        uint64_t tpc[MaxTL];	// Trap Program Counter (value from
                                // previous trap level)
        uint64_t tnpc[MaxTL];	// Trap Next Program Counter (value from
                                // previous trap level)
        union
        {
            uint64_t tstate[MaxTL];	// Trap State
            struct
            {
                //Values are from previous trap level
                uint64_t cwp:5;		// Current Window Pointer
                uint64_t :2;	// Reserved bits
                uint64_t pstate:10;	// Process State
                uint64_t :6;	// Reserved bits
                uint64_t asi:8;		// Address Space Identifier
                uint64_t ccr:8;		// Condition Code Register
            } tstateFields[MaxTL];
        };
        union
        {
            uint64_t tick;		// Hardware clock-tick counter
            struct
            {
                uint64_t counter:63;	// Clock-tick count
                uint64_t npt:1;		// Non-priveleged trap
            } tickFields;
        };
        uint8_t cansave;	// Savable windows
        uint8_t canrestore;	// Restorable windows
        uint8_t otherwin;	// Other windows
        uint8_t cleanwin;	// Clean windows
        union
        {
            uint8_t wstate;		// Window State
            struct
            {
                uint8_t normal:3;	// Bits TT<4:2> are set to on a normal
                                        // register window trap
                uint8_t other:3;	// Bits TT<4:2> are set to on an "otherwin"
                                        // register window trap
            } wstateFields;
        };
        union
        {
            uint64_t ver;		// Version
            struct
            {
                uint64_t maxwin:5;	// Max CWP value
                uint64_t :2;	// Reserved bits
                uint64_t maxtl:8;	// Maximum trap level
                uint64_t :8;	// Reserved bits
                uint64_t mask:8;	// Processor mask set revision number
                uint64_t impl:16;	// Implementation identification number
                uint64_t manuf:16;	// Manufacturer code
            } verFields;
        };
        union
        {
            uint64_t	fsr;	// Floating-Point State Register
            struct
            {
                union
                {
                    uint64_t cexc:5;	// Current excpetion
                    struct
                    {
                        uint64_t nxc:1;		// Inexact
                        uint64_t dzc:1;		// Divide by zero
                        uint64_t ufc:1;		// Underflow
                        uint64_t ofc:1;		// Overflow
                        uint64_t nvc:1;		// Invalid operand
                    } cexecFields;
                };
                union
                {
                    uint64_t aexc:5;		// Accrued exception
                    struct
                    {
                        uint64_t nxc:1;		// Inexact
                        uint64_t dzc:1;		// Divide by zero
                        uint64_t ufc:1;		// Underflow
                        uint64_t ofc:1;		// Overflow
                        uint64_t nvc:1;		// Invalid operand
                    } aexecFields;
                };
                uint64_t fcc0:2;		// Floating-Point condtion codes
                uint64_t :1;		// Reserved bits
                uint64_t qne:1;			// Deferred trap queue not empty
                                                // with no queue, it should read 0
                uint64_t ftt:3;			// Floating-Point trap type
                uint64_t ver:3;			// Version (of the FPU)
                uint64_t :2;		// Reserved bits
                uint64_t ns:1;			// Nonstandard floating point
                union
                {
                    uint64_t tem:5;			// Trap Enable Mask
                    struct
                    {
                        uint64_t nxm:1;		// Inexact
                        uint64_t dzm:1;		// Divide by zero
                        uint64_t ufm:1;		// Underflow
                        uint64_t ofm:1;		// Overflow
                        uint64_t nvm:1;		// Invalid operand
                    } temFields;
                };
                uint64_t :2;		// Reserved bits
                uint64_t rd:2;			// Rounding direction
                uint64_t fcc1:2;		// Floating-Point condition codes
                uint64_t fcc2:2;		// Floating-Point condition codes
                uint64_t fcc3:2;		// Floating-Point condition codes
                uint64_t :26;		// Reserved bits
            } fsrFields;
        };
        union
        {
            uint8_t		fprs;	// Floating-Point Register State
            struct
            {
                uint8_t dl:1;		// Dirty lower
                uint8_t du:1;		// Dirty upper
                uint8_t fef:1;		// FPRS enable floating-Point
            } fprsFields;
        };

      public:
        MiscReg readReg(int misc_reg);

        MiscReg readRegWithEffect(int misc_reg, Fault &fault, ExecContext *xc);

        Fault setReg(int misc_reg, const MiscReg &val);

        Fault setRegWithEffect(int misc_reg, const MiscReg &val,
                               ExecContext *xc);

        void serialize(std::ostream & os);

        void unserialize(Checkpoint * cp, std::string & section);
    };

    typedef union
    {
        float32_t singReg;
        float64_t doubReg;
        float128_t quadReg;
    } FloatReg;

    typedef union
    {
        IntReg  intreg;
        FloatReg   fpreg;
        MiscReg ctrlreg;
    } AnyReg;

    struct RegFile
    {
        IntRegFile intRegFile;		// (signed) integer register file
        FloatRegFile floatRegFile;	// floating point register file
        MiscRegFile miscRegFile;	// control register file

        Addr pc;		// Program Counter
        Addr npc;		// Next Program Counter

        void serialize(std::ostream &os);
        void unserialize(Checkpoint *cp, const std::string &section);
    };

    StaticInstPtr decodeInst(MachInst);

    // return a no-op instruction... used for instruction fetch faults
    extern const MachInst NoopMachInst;

    // Instruction address compression hooks
    inline Addr realPCToFetchPC(const Addr &addr)
    {
        return addr;
    }

    inline Addr fetchPCToRealPC(const Addr &addr)
    {
        return addr;
    }

    // the size of "fetched" instructions (not necessarily the size
    // of real instructions for PISA)
    inline size_t fetchInstSize()
    {
        return sizeof(MachInst);
    }

    /**
     * Function to insure ISA semantics about 0 registers.
     * @param xc The execution context.
     */
    template <class XC>
    void zeroRegisters(XC *xc);
};

#if !FULL_SYSTEM
class SyscallReturn
{
  public:
    template <class T>
    SyscallReturn(T v, bool s)
    {
        retval = (uint64_t)v;
        success = s;
    }

    template <class T>
    SyscallReturn(T v)
    {
        success = (v >= 0);
        retval = (uint64_t)v;
    }

    ~SyscallReturn() {}

    SyscallReturn& operator=(const SyscallReturn& s)
    {
        retval = s.retval;
        success = s.success;
        return *this;
    }

    bool successful() { return success; }
    uint64_t value() { return retval; }

    private:
    uint64_t retval;
    bool success;
};

#endif


#if FULL_SYSTEM

#include "arch/alpha/ev5.hh"
#endif

#endif // __ARCH_SPARC_ISA_TRAITS_HH__