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

// This template provides the execute functions for a swap
def template SwapExecute {{
        Fault %(class_name)s::execute(ExecContext *xc,
                trace::InstRecord *traceData) const
        {
            Fault fault = NoFault;
            // This is to support the conditional store in cas instructions.
            // It should be optomized out in all the others
            bool storeCond = true;
            Addr EA;
            %(op_decl)s;
            uint64_t mem_data = 0;

            %(op_rd)s;
            %(ea_code)s;
            DPRINTF(Sparc, "%s: The address is 0x%x\n", mnemonic, EA);
            %(fault_check)s;
            if (fault == NoFault) {
                %(code)s;
            }
            if (storeCond && fault == NoFault) {
                %(EA_trunc)s
                fault = writeMemAtomicBE(xc, traceData, Mem, EA,
                        %(asi_val)s, &mem_data);
            }
            if (fault == NoFault) {
                // Handle the swapping
                %(postacc_code)s;
            }
            if (fault == NoFault) {
                // Write the resulting state to the execution context
                %(op_wb)s;
            }

            return fault;
        }
}};


def template SwapInitiateAcc {{
        Fault %(class_name)s::initiateAcc(ExecContext * xc,
                trace::InstRecord * traceData) const
        {
            Fault fault = NoFault;
            Addr EA;
            uint64_t mem_data = 0;
            %(op_decl)s;
            %(op_rd)s;
            %(ea_code)s;

            DPRINTF(Sparc, "%s: The address is 0x%x\n", mnemonic, EA);
            %(fault_check)s;

            if (fault == NoFault) {
                %(code)s;
            }
            if (fault == NoFault) {
                %(EA_trunc)s
                fault = writeMemTimingBE(xc, traceData, Mem, EA, %(asi_val)s,
                        &mem_data);
            }
            return fault;
        }
}};



def template SwapCompleteAcc {{
        Fault %(class_name)s::completeAcc(PacketPtr pkt, ExecContext * xc,
                trace::InstRecord * traceData) const
        {
            Fault fault = NoFault;
            %(op_decl)s;

            getMemBE(pkt, Mem, traceData);
            uint64_t mem_data = Mem;

            if (fault == NoFault) {
                // Handle the swapping
                %(postacc_code)s;
            }
            if (fault == NoFault) {
                // Write the resulting state to the execution context
                %(op_wb)s;
            }

            return fault;
        }
}};

let {{
    SwapFuncs = [SwapExecute, SwapInitiateAcc, SwapCompleteAcc]
}};


def format Swap(code, postacc_code, mem_flags, *opt_flags) {{
    mem_flags = makeList(mem_flags)
    mem_flags = [ 'Request::%s' % flag for flag in mem_flags ]
    flags = '|'.join(mem_flags)

    (header_output,
     decoder_output,
     exec_output,
     decode_block) = doMemFormat(code, SwapFuncs, '', name, Name, flags,
         ["IsStoreConditional"], postacc_code)
}};

def format SwapAlt(code, postacc_code, mem_flags, *opt_flags) {{
    mem_flags = makeList(mem_flags)
    mem_flags = [ 'Request::%s' % flag for flag in mem_flags ]
    mem_flags.append("EXT_ASI")
    flags = '|'.join(mem_flags)
    (header_output,
     decoder_output,
     exec_output,
     decode_block) = doMemFormat(code, SwapFuncs, AlternateASIPrivFaultCheck,
         name, Name, flags, ["IsStoreConditional"], postacc_code)
}};


let {{
    def doCasFormat(code, execute, faultCode, name, Name, mem_flags, opt_flags, postacc_code = ''):
        addrCalcReg = 'EA = Rs1;'
        iop = InstObjParams(name, Name, 'Mem',
                {"code": code, "postacc_code" : postacc_code,
                 "fault_check": faultCode, "ea_code": addrCalcReg,
                 "EA_trunc" : TruncateEA}, opt_flags)
        header_output = MemDeclare.subst(iop)
        decoder_output = BasicConstructor.subst(iop)
        decode_block = BasicDecode.subst(iop)
        microParams = {"code": code, "postacc_code" : postacc_code,
            "ea_code" : addrCalcReg, "fault_check" : faultCode,
            "EA_trunc" : TruncateEA}
        exec_output = doSplitExecute(execute, name, Name, mem_flags,
                ["IsStoreConditional"], microParams);
        return (header_output, decoder_output, exec_output, decode_block)
}};


def format CasAlt(code, postacc_code, mem_flags, *opt_flags) {{
    mem_flags = makeList(mem_flags)
    mem_flags = [ 'Request::%s' % flag for flag in mem_flags ]
    mem_flags.append("EXT_ASI")
    flags = '|'.join(mem_flags)
    (header_output,
     decoder_output,
     exec_output,
     decode_block) = doCasFormat(code, SwapFuncs, AlternateASIPrivFaultCheck,
         name, Name, flags, ["IsStoreConditional"], postacc_code)
}};
