// -*- mode:c++ -*-

// Copyright (c) 2010 ARM Limited
// All rights reserved
//
// The license below extends only to copyright in the software and shall
// not be construed as granting a license to any other intellectual
// property including but not limited to intellectual property relating
// to a hardware implementation of the functionality of the software
// licensed hereunder.  You may use the software subject to the license
// terms below provided that you ensure that this notice is replicated
// unmodified and in its entirety in all distributions of the software,
// modified or unmodified, in source code or in binary form.
//
// 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

let {{
    def loadStoreBaseWork(name, Name, imm, swp, rfe, codeBlobs, memFlags,
                          instFlags, double, strex, base = 'Memory',
                          execTemplateBase = ''):
        # Make sure flags are in lists (convert to lists if not).
        memFlags = makeList(memFlags)
        instFlags = makeList(instFlags)

        eaCode = codeBlobs["ea_code"]

        # This shouldn't be part of the eaCode, but until the exec templates
        # are converted over it's the easiest place to put it.
        eaCode += '\n    unsigned memAccessFlags = '
        eaCode += (string.join(memFlags, '|') + ';')

        codeBlobs["ea_code"] = eaCode

        iop = InstObjParams(name, Name, base, codeBlobs, instFlags)

        fullExecTemplate = eval(execTemplateBase + 'Execute')
        initiateAccTemplate = eval(execTemplateBase + 'InitiateAcc')
        completeAccTemplate = eval(execTemplateBase + 'CompleteAcc')

        if swp:
            declareTemplate = SwapDeclare
            constructTemplate = SwapConstructor
        elif rfe:
            declareTemplate = RfeDeclare
            constructTemplate = RfeConstructor
        elif imm:
            if double:
                declareTemplate = LoadStoreDImmDeclare
                constructTemplate = LoadStoreDImmConstructor
                if strex:
                    declareTemplate = StoreExDImmDeclare
                    constructTemplate = StoreExDImmConstructor
            elif strex:
                declareTemplate = StoreExImmDeclare
                constructTemplate = StoreExImmConstructor
            else:
                declareTemplate = LoadStoreImmDeclare
                constructTemplate = LoadStoreImmConstructor
        else:
            if double:
                declareTemplate = LoadStoreDRegDeclare
                constructTemplate = LoadStoreDRegConstructor
            else:
                declareTemplate = LoadStoreRegDeclare
                constructTemplate = LoadStoreRegConstructor

        # (header_output, decoder_output, decode_block, exec_output)
        return (declareTemplate.subst(iop),
                constructTemplate.subst(iop),
                fullExecTemplate.subst(iop)
                + initiateAccTemplate.subst(iop)
                + completeAccTemplate.subst(iop))

    def loadStoreBase(name, Name, imm, eaCode, accCode, postAccCode,
                      memFlags, instFlags, double, strex, base = 'Memory',
                      execTemplateBase = ''):
        codeBlobs = { "ea_code": eaCode,
                      "memacc_code": accCode,
                      "postacc_code": postAccCode,
                      "predicate_test": predicateTest }
        return loadStoreBaseWork(name, Name, imm, False, False, codeBlobs,
                                 memFlags, instFlags, double, strex, base,
                                 execTemplateBase)

    def RfeBase(name, Name, eaCode, accCode, memFlags, instFlags):
        codeBlobs = { "ea_code": eaCode,
                      "memacc_code": accCode,
                      "predicate_test": predicateTest }
        return loadStoreBaseWork(name, Name, False, False, True, codeBlobs,
                                 memFlags, instFlags, False, False,
                                 'RfeOp', 'Load')

    def SwapBase(name, Name, eaCode, preAccCode, postAccCode, memFlags,
                 instFlags):
        codeBlobs = { "ea_code": eaCode,
                      "preacc_code": preAccCode,
                      "postacc_code": postAccCode,
                      "predicate_test": predicateTest }
        return loadStoreBaseWork(name, Name, False, True, False, codeBlobs,
                                 memFlags, instFlags, False, False,
                                 'Swap', 'Swap')

    def memClassName(base, post, add, writeback, \
                     size=4, sign=False, user=False):
        Name = base

        if post:
            Name += '_PY'
        else:
            Name += '_PN'

        if add:
            Name += '_AY'
        else:
            Name += '_AN'

        if writeback:
            Name += '_WY'
        else:
            Name += '_WN'

        Name += ('_SZ%d' % size)

        if sign:
            Name += '_SY'
        else:
            Name += '_SN'

        if user:
            Name += '_UY'
        else:
            Name += '_UN'

        return Name

    def buildMemSuffix(sign, size):
        if size == 4:
            memSuffix = ''
        elif size == 2:
            if sign:
                memSuffix = '.sh'
            else:
                memSuffix = '.uh'
        elif size == 1:
            if sign:
                memSuffix = '.sb'
            else:
                memSuffix = '.ub'
        else:
            raise Exception, "Unrecognized size for load %d" % size

        return memSuffix

    def buildMemBase(base, post, writeback):
        if post and writeback:
            base = "MemoryPostIndex<%s>" % base
        elif not post and writeback:
            base = "MemoryPreIndex<%s>" % base
        elif not post and not writeback:
            base = "MemoryOffset<%s>" % base
        else:
            raise Exception, "Illegal combination of post and writeback"
        return base
}};