// Copyright (c) 2007-2008 The Hewlett-Packard Development Company
// Copyright (c) 2015 Advanced Micro Devices, Inc.
// 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.
//
// Copyright (c) 2008 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

//////////////////////////////////////////////////////////////////////////
//
// LdStOp Microop templates
//
//////////////////////////////////////////////////////////////////////////

// LEA template

def template MicroLeaExecute {{
    Fault %(class_name)s::execute(ExecContext *xc,
          Trace::InstRecord *traceData) const
    {
        Fault fault = NoFault;
        Addr EA;

        %(op_decl)s;
        %(op_rd)s;
        %(ea_code)s;
        DPRINTF(X86, "%s : %s: The address is %#x\n", instMnem, mnemonic, EA);

        %(code)s;
        if(fault == NoFault)
        {
            %(op_wb)s;
        }

        return fault;
    }
}};

def template MicroLeaDeclare {{
    class %(class_name)s : public %(base_class)s
    {
      public:
        %(class_name)s(ExtMachInst _machInst,
                const char * instMnem, uint64_t setFlags,
                uint8_t _scale, InstRegIndex _index, InstRegIndex _base,
                uint64_t _disp, InstRegIndex _segment,
                InstRegIndex _data,
                uint8_t _dataSize, uint8_t _addressSize,
                Request::FlagsType _memFlags);

        Fault execute(ExecContext *, Trace::InstRecord *) const;
    };
}};

// Load templates

def template MicroLoadExecute {{
    Fault %(class_name)s::execute(ExecContext *xc,
          Trace::InstRecord *traceData) const
    {
        Fault fault = NoFault;
        Addr EA;

        %(op_decl)s;
        %(op_rd)s;
        %(ea_code)s;
        DPRINTF(X86, "%s : %s: The address is %#x\n", instMnem, mnemonic, EA);

        fault = readMemAtomic(xc, traceData, EA, Mem, dataSize, memFlags);

        if (fault == NoFault) {
            %(code)s;
        } else if (memFlags & Request::PREFETCH) {
            // For prefetches, ignore any faults/exceptions.
            return NoFault;
        }
        if(fault == NoFault)
        {
            %(op_wb)s;
        }

        return fault;
    }
}};

def template MicroLoadInitiateAcc {{
    Fault %(class_name)s::initiateAcc(ExecContext * xc,
            Trace::InstRecord * traceData) const
    {
        Fault fault = NoFault;
        Addr EA;

        %(op_decl)s;
        %(op_rd)s;
        %(ea_code)s;
        DPRINTF(X86, "%s : %s: The address is %#x\n", instMnem, mnemonic, EA);

        fault = initiateMemRead(xc, traceData, EA,
                                %(memDataSize)s, memFlags);

        return fault;
    }
}};

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

        %(op_decl)s;
        %(op_rd)s;

        getMem(pkt, Mem, dataSize, traceData);

        %(code)s;

        if(fault == NoFault)
        {
            %(op_wb)s;
        }

        return fault;
    }
}};

// Store templates

def template MicroStoreExecute {{
    Fault %(class_name)s::execute(ExecContext * xc,
            Trace::InstRecord *traceData) const
    {
        Fault fault = NoFault;

        Addr EA;
        %(op_decl)s;
        %(op_rd)s;
        %(ea_code)s;
        DPRINTF(X86, "%s : %s: The address is %#x\n", instMnem, mnemonic, EA);

        %(code)s;

        if (fault == NoFault) {
            fault = writeMemAtomic(xc, traceData, Mem, dataSize, EA,
                                   memFlags, NULL);
            if (fault == NoFault) {
                %(op_wb)s;
            }
        }

        return fault;
    }
}};

def template MicroStoreInitiateAcc {{
    Fault %(class_name)s::initiateAcc(ExecContext * xc,
            Trace::InstRecord * traceData) const
    {
        Fault fault = NoFault;

        Addr EA;
        %(op_decl)s;
        %(op_rd)s;
        %(ea_code)s;
        DPRINTF(X86, "%s : %s: The address is %#x\n", instMnem, mnemonic, EA);

        %(code)s;

        if (fault == NoFault) {
            fault = writeMemTiming(xc, traceData, Mem, dataSize, EA,
                                   memFlags, NULL);
        }
        return fault;
    }
}};

def template MicroStoreCompleteAcc {{
    Fault %(class_name)s::completeAcc(PacketPtr pkt,
            ExecContext * xc, Trace::InstRecord * traceData) const
    {
        %(op_decl)s;
        %(op_rd)s;
        %(complete_code)s;
        %(op_wb)s;
        return NoFault;
    }
}};

def template MicroLdStOpDeclare {{
    class %(class_name)s : public %(base_class)s
    {
      public:
        %(class_name)s(ExtMachInst _machInst,
                const char * instMnem, uint64_t setFlags,
                uint8_t _scale, InstRegIndex _index, InstRegIndex _base,
                uint64_t _disp, InstRegIndex _segment,
                InstRegIndex _data,
                uint8_t _dataSize, uint8_t _addressSize,
                Request::FlagsType _memFlags);

        Fault execute(ExecContext *, Trace::InstRecord *) const;
        Fault initiateAcc(ExecContext *, Trace::InstRecord *) const;
        Fault completeAcc(PacketPtr, ExecContext *, Trace::InstRecord *) const;
    };
}};

// LdStSplitOp is a load or store that uses a pair of regs as the
// source or destination.  Used for cmpxchg{8,16}b.
def template MicroLdStSplitOpDeclare {{
    class %(class_name)s : public %(base_class)s
    {
      public:
        %(class_name)s(ExtMachInst _machInst,
                const char * instMnem, uint64_t setFlags,
                uint8_t _scale, InstRegIndex _index, InstRegIndex _base,
                uint64_t _disp, InstRegIndex _segment,
                InstRegIndex _dataLow, InstRegIndex _dataHi,
                uint8_t _dataSize, uint8_t _addressSize,
                Request::FlagsType _memFlags);

        Fault execute(ExecContext *, Trace::InstRecord *) const;
        Fault initiateAcc(ExecContext *, Trace::InstRecord *) const;
        Fault completeAcc(PacketPtr, ExecContext *, Trace::InstRecord *) const;
    };
}};

def template MicroLdStOpConstructor {{
    %(class_name)s::%(class_name)s(
            ExtMachInst machInst, const char * instMnem, uint64_t setFlags,
            uint8_t _scale, InstRegIndex _index, InstRegIndex _base,
            uint64_t _disp, InstRegIndex _segment,
            InstRegIndex _data,
            uint8_t _dataSize, uint8_t _addressSize,
            Request::FlagsType _memFlags) :
        %(base_class)s(machInst, "%(mnemonic)s", instMnem, setFlags,
                _scale, _index, _base,
                _disp, _segment, _data,
                _dataSize, _addressSize, _memFlags, %(op_class)s)
    {
        %(constructor)s;
    }
}};

def template MicroLdStSplitOpConstructor {{
    %(class_name)s::%(class_name)s(
            ExtMachInst machInst, const char * instMnem, uint64_t setFlags,
            uint8_t _scale, InstRegIndex _index, InstRegIndex _base,
            uint64_t _disp, InstRegIndex _segment,
            InstRegIndex _dataLow, InstRegIndex _dataHi,
            uint8_t _dataSize, uint8_t _addressSize,
            Request::FlagsType _memFlags) :
        %(base_class)s(machInst, "%(mnemonic)s", instMnem, setFlags,
                _scale, _index, _base,
                _disp, _segment, _dataLow, _dataHi,
                _dataSize, _addressSize, _memFlags, %(op_class)s)
    {
        %(constructor)s;
    }
}};

let {{
    class LdStOp(X86Microop):
        def __init__(self, data, segment, addr, disp,
                dataSize, addressSize, baseFlags, atCPL0, prefetch, nonSpec,
                implicitStack, uncacheable):
            self.data = data
            [self.scale, self.index, self.base] = addr
            self.disp = disp
            self.segment = segment
            self.dataSize = dataSize
            self.addressSize = addressSize
            self.memFlags = baseFlags
            if atCPL0:
                self.memFlags += " | (CPL0FlagBit << FlagShift)"
            self.instFlags = ""
            if prefetch:
                self.memFlags += " | Request::PREFETCH"
                self.instFlags += " | (1ULL << StaticInst::IsDataPrefetch)"
            if nonSpec:
                self.instFlags += " | (1ULL << StaticInst::IsNonSpeculative)"
            if uncacheable:
                self.instFlags += " | (Request::UNCACHEABLE)"
            # For implicit stack operations, we should use *not* use the
            # alternative addressing mode for loads/stores if the prefix is set
            if not implicitStack:
                self.memFlags += " | (machInst.legacy.addr ? " + \
                                 "(AddrSizeFlagBit << FlagShift) : 0)"

        def getAllocator(self, microFlags):
            allocator = '''new %(class_name)s(machInst, macrocodeBlock,
                    %(flags)s, %(scale)s, %(index)s, %(base)s,
                    %(disp)s, %(segment)s, %(data)s,
                    %(dataSize)s, %(addressSize)s, %(memFlags)s)''' % {
                "class_name" : self.className,
                "flags" : self.microFlagsText(microFlags) + self.instFlags,
                "scale" : self.scale, "index" : self.index,
                "base" : self.base,
                "disp" : self.disp,
                "segment" : self.segment, "data" : self.data,
                "dataSize" : self.dataSize, "addressSize" : self.addressSize,
                "memFlags" : self.memFlags}
            return allocator

    class BigLdStOp(X86Microop):
        def __init__(self, data, segment, addr, disp,
                dataSize, addressSize, baseFlags, atCPL0, prefetch, nonSpec,
                implicitStack, uncacheable):
            self.data = data
            [self.scale, self.index, self.base] = addr
            self.disp = disp
            self.segment = segment
            self.dataSize = dataSize
            self.addressSize = addressSize
            self.memFlags = baseFlags
            if atCPL0:
                self.memFlags += " | (CPL0FlagBit << FlagShift)"
            self.instFlags = ""
            if prefetch:
                self.memFlags += " | Request::PREFETCH"
                self.instFlags += " | (1ULL << StaticInst::IsDataPrefetch)"
            if nonSpec:
                self.instFlags += " | (1ULL << StaticInst::IsNonSpeculative)"
            if uncacheable:
                self.instFlags += " | (Request::UNCACHEABLE)"
            # For implicit stack operations, we should use *not* use the
            # alternative addressing mode for loads/stores if the prefix is set
            if not implicitStack:
                self.memFlags += " | (machInst.legacy.addr ? " + \
                                 "(AddrSizeFlagBit << FlagShift) : 0)"

        def getAllocator(self, microFlags):
            allocString = '''
                (%(dataSize)s >= 4) ?
                    (StaticInstPtr)(new %(class_name)sBig(machInst,
                        macrocodeBlock, %(flags)s, %(scale)s, %(index)s,
                        %(base)s, %(disp)s, %(segment)s, %(data)s,
                        %(dataSize)s, %(addressSize)s, %(memFlags)s)) :
                    (StaticInstPtr)(new %(class_name)s(machInst,
                        macrocodeBlock, %(flags)s, %(scale)s, %(index)s,
                        %(base)s, %(disp)s, %(segment)s, %(data)s,
                        %(dataSize)s, %(addressSize)s, %(memFlags)s))
            '''
            allocator = allocString % {
                "class_name" : self.className,
                "flags" : self.microFlagsText(microFlags) + self.instFlags,
                "scale" : self.scale, "index" : self.index,
                "base" : self.base,
                "disp" : self.disp,
                "segment" : self.segment, "data" : self.data,
                "dataSize" : self.dataSize, "addressSize" : self.addressSize,
                "memFlags" : self.memFlags}
            return allocator

    class LdStSplitOp(LdStOp):
        def __init__(self, data, segment, addr, disp,
                dataSize, addressSize, baseFlags, atCPL0, prefetch, nonSpec,
                implicitStack, uncacheable):
            super(LdStSplitOp, self).__init__(0, segment, addr, disp,
                dataSize, addressSize, baseFlags, atCPL0, prefetch, nonSpec,
                implicitStack, uncacheable)
            (self.dataLow, self.dataHi) = data

        def getAllocator(self, microFlags):
            allocString = '''(StaticInstPtr)(new %(class_name)s(machInst,
                        macrocodeBlock, %(flags)s, %(scale)s, %(index)s,
                        %(base)s, %(disp)s, %(segment)s,
                        %(dataLow)s, %(dataHi)s,
                        %(dataSize)s, %(addressSize)s, %(memFlags)s))
            '''
            allocator = allocString % {
                "class_name" : self.className,
                "flags" : self.microFlagsText(microFlags) + self.instFlags,
                "scale" : self.scale, "index" : self.index,
                "base" : self.base,
                "disp" : self.disp,
                "segment" : self.segment,
                "dataLow" : self.dataLow, "dataHi" : self.dataHi,
                "dataSize" : self.dataSize, "addressSize" : self.addressSize,
                "memFlags" : self.memFlags}
            return allocator

}};

let {{

    # Make these empty strings so that concatenating onto
    # them will always work.
    header_output = ""
    decoder_output = ""
    exec_output = ""

    segmentEAExpr = \
        'bits(scale * Index + Base + disp, addressSize * 8 - 1, 0);'

    calculateEA = 'EA = SegBase + ' + segmentEAExpr

    def defineMicroLoadOp(mnemonic, code, bigCode='',
                          mem_flags="0", big=True, nonSpec=False,
                          implicitStack=False):
        global header_output
        global decoder_output
        global exec_output
        global microopClasses
        Name = mnemonic
        name = mnemonic.lower()

        # Build up the all register version of this micro op
        iops = [InstObjParams(name, Name, 'X86ISA::LdStOp',
                              { "code": code,
                                "ea_code": calculateEA,
                                "memDataSize": "dataSize" })]
        if big:
            iops += [InstObjParams(name, Name + "Big", 'X86ISA::LdStOp',
                                   { "code": bigCode,
                                     "ea_code": calculateEA,
                                     "memDataSize": "dataSize" })]
        for iop in iops:
            header_output += MicroLdStOpDeclare.subst(iop)
            decoder_output += MicroLdStOpConstructor.subst(iop)
            exec_output += MicroLoadExecute.subst(iop)
            exec_output += MicroLoadInitiateAcc.subst(iop)
            exec_output += MicroLoadCompleteAcc.subst(iop)

        if implicitStack:
            # For instructions that implicitly access the stack, the address
            # size is the same as the stack segment pointer size, not the
            # address size if specified by the instruction prefix
            addressSize = "env.stackSize"
        else:
            addressSize = "env.addressSize"

        base = LdStOp
        if big:
            base = BigLdStOp
        class LoadOp(base):
            def __init__(self, data, segment, addr, disp = 0,
                    dataSize="env.dataSize",
                    addressSize=addressSize,
                    atCPL0=False, prefetch=False, nonSpec=nonSpec,
                    implicitStack=implicitStack, uncacheable=False):
                super(LoadOp, self).__init__(data, segment, addr,
                        disp, dataSize, addressSize, mem_flags,
                        atCPL0, prefetch, nonSpec, implicitStack, uncacheable)
                self.className = Name
                self.mnemonic = name

        microopClasses[name] = LoadOp

    defineMicroLoadOp('Ld', 'Data = merge(Data, Mem, dataSize);',
                            'Data = Mem & mask(dataSize * 8);')
    defineMicroLoadOp('Ldis', 'Data = merge(Data, Mem, dataSize);',
                              'Data = Mem & mask(dataSize * 8);',
                               implicitStack=True)
    defineMicroLoadOp('Ldst', 'Data = merge(Data, Mem, dataSize);',
                              'Data = Mem & mask(dataSize * 8);',
                      '(StoreCheck << FlagShift)')
    defineMicroLoadOp('Ldstl', 'Data = merge(Data, Mem, dataSize);',
                               'Data = Mem & mask(dataSize * 8);',
                      '(StoreCheck << FlagShift) | Request::LOCKED_RMW',
                      nonSpec=True)

    defineMicroLoadOp('Ldfp', code='FpData_uqw = Mem', big = False)

    defineMicroLoadOp('Ldfp87', code='''
        switch (dataSize)
        {
          case 4:
            FpData_df = *(float *)&Mem;
            break;
          case 8:
            FpData_df = *(double *)&Mem;
            break;
          default:
            panic("Unhandled data size in LdFp87.\\n");
        }
    ''', big = False)

    # Load integer from memory into x87 top-of-stack register.
    # Used to implement fild instruction.
    defineMicroLoadOp('Ldifp87', code='''
        switch (dataSize)
        {
          case 2:
            FpData_df = (int64_t)sext<16>(Mem);
            break;
          case 4:
            FpData_df = (int64_t)sext<32>(Mem);
            break;
          case 8:
            FpData_df = (int64_t)Mem;
            break;
          default:
            panic("Unhandled data size in LdIFp87.\\n");
        }
    ''', big = False)

    def defineMicroLoadSplitOp(mnemonic, code, mem_flags="0", nonSpec=False):
        global header_output
        global decoder_output
        global exec_output
        global microopClasses
        Name = mnemonic
        name = mnemonic.lower()

        iop = InstObjParams(name, Name, 'X86ISA::LdStSplitOp',
                            { "code": code,
                              "ea_code": calculateEA,
                              "memDataSize": "2 * dataSize" })

        header_output += MicroLdStSplitOpDeclare.subst(iop)
        decoder_output += MicroLdStSplitOpConstructor.subst(iop)
        exec_output += MicroLoadExecute.subst(iop)
        exec_output += MicroLoadInitiateAcc.subst(iop)
        exec_output += MicroLoadCompleteAcc.subst(iop)

        class LoadOp(LdStSplitOp):
            def __init__(self, data, segment, addr, disp = 0,
                    dataSize="env.dataSize",
                    addressSize="env.addressSize",
                    atCPL0=False, prefetch=False, nonSpec=nonSpec,
                    implicitStack=False, uncacheable=False):
                super(LoadOp, self).__init__(data, segment, addr,
                        disp, dataSize, addressSize, mem_flags,
                        atCPL0, prefetch, nonSpec, implicitStack, uncacheable)
                self.className = Name
                self.mnemonic = name

        microopClasses[name] = LoadOp

    code = '''
        DataLow = Mem_u2qw[0];
        DataHi = Mem_u2qw[1];
    '''

    defineMicroLoadSplitOp('LdSplit', code,
                           '(StoreCheck << FlagShift)')

    defineMicroLoadSplitOp('LdSplitl', code,
                           '(StoreCheck << FlagShift) | Request::LOCKED_RMW',
                           nonSpec=True)

    def defineMicroStoreOp(mnemonic, code, completeCode="", mem_flags="0",
                           implicitStack=False):
        global header_output
        global decoder_output
        global exec_output
        global microopClasses
        Name = mnemonic
        name = mnemonic.lower()

        # Build up the all register version of this micro op
        iop = InstObjParams(name, Name, 'X86ISA::LdStOp',
                            { "code": code,
                              "complete_code": completeCode,
                              "ea_code": calculateEA,
                              "memDataSize": "dataSize" })
        header_output += MicroLdStOpDeclare.subst(iop)
        decoder_output += MicroLdStOpConstructor.subst(iop)
        exec_output += MicroStoreExecute.subst(iop)
        exec_output += MicroStoreInitiateAcc.subst(iop)
        exec_output += MicroStoreCompleteAcc.subst(iop)

        if implicitStack:
            # For instructions that implicitly access the stack, the address
            # size is the same as the stack segment pointer size, not the
            # address size if specified by the instruction prefix
            addressSize = "env.stackSize"
        else:
            addressSize = "env.addressSize"

        class StoreOp(LdStOp):
            def __init__(self, data, segment, addr, disp = 0,
                    dataSize="env.dataSize",
                    addressSize=addressSize,
                    atCPL0=False, nonSpec=False, implicitStack=implicitStack,
                    uncacheable=False):
                super(StoreOp, self).__init__(data, segment, addr, disp,
                        dataSize, addressSize, mem_flags, atCPL0, False,
                        nonSpec, implicitStack, uncacheable)
                self.className = Name
                self.mnemonic = name

        microopClasses[name] = StoreOp

    defineMicroStoreOp('St', 'Mem = pick(Data, 2, dataSize);')
    defineMicroStoreOp('Stis', 'Mem = pick(Data, 2, dataSize);',
                       implicitStack=True)
    defineMicroStoreOp('Stul', 'Mem = pick(Data, 2, dataSize);',
            mem_flags="Request::LOCKED_RMW")

    defineMicroStoreOp('Stfp', code='Mem = FpData_uqw;')

    defineMicroStoreOp('Stfp87', code='''
        switch (dataSize)
        {
          case 4: {
            float single(FpData_df);
            Mem = *(uint32_t *)&single;
          } break;
          case 8:
            Mem = *(uint64_t *)&FpData_df;
            break;
          default:
            panic("Unhandled data size in StFp87.\\n");
        }
    ''')

    defineMicroStoreOp('Cda', 'Mem = 0;', mem_flags="Request::NO_ACCESS")
    defineMicroStoreOp('Clflushopt', 'Mem = 0;',
                       mem_flags="Request::CLEAN | Request::INVALIDATE" +
                       " | Request::DST_POC")
    defineMicroStoreOp('Clwb', 'Mem = 0;',
                       mem_flags="Request::CLEAN | Request::DST_POC")

    def defineMicroStoreSplitOp(mnemonic, code,
                                completeCode="", mem_flags="0"):
        global header_output
        global decoder_output
        global exec_output
        global microopClasses
        Name = mnemonic
        name = mnemonic.lower()

        iop = InstObjParams(name, Name, 'X86ISA::LdStSplitOp',
                            { "code": code,
                              "complete_code": completeCode,
                              "ea_code": calculateEA,
                              "memDataSize": "2 * dataSize" })

        header_output += MicroLdStSplitOpDeclare.subst(iop)
        decoder_output += MicroLdStSplitOpConstructor.subst(iop)
        exec_output += MicroStoreExecute.subst(iop)
        exec_output += MicroStoreInitiateAcc.subst(iop)
        exec_output += MicroStoreCompleteAcc.subst(iop)

        class StoreOp(LdStSplitOp):
            def __init__(self, data, segment, addr, disp = 0,
                    dataSize="env.dataSize",
                    addressSize="env.addressSize",
                    atCPL0=False, nonSpec=False, implicitStack=False,
                    uncacheable=False):
                super(StoreOp, self).__init__(data, segment, addr, disp,
                        dataSize, addressSize, mem_flags, atCPL0, False,
                        nonSpec, implicitStack, uncacheable)
                self.className = Name
                self.mnemonic = name

        microopClasses[name] = StoreOp

    code = '''
        Mem_u2qw[0] = DataLow;
        Mem_u2qw[1] = DataHi;
    '''

    defineMicroStoreSplitOp('StSplit', code);

    defineMicroStoreSplitOp('StSplitul', code,
                            mem_flags='Request::LOCKED_RMW')

    iop = InstObjParams("lea", "Lea", 'X86ISA::LdStOp',
                        { "code": "Data = merge(Data, EA, dataSize);",
                          "ea_code": "EA = " + segmentEAExpr,
                          "memDataSize": "dataSize" })
    header_output += MicroLeaDeclare.subst(iop)
    decoder_output += MicroLdStOpConstructor.subst(iop)
    exec_output += MicroLeaExecute.subst(iop)

    class LeaOp(LdStOp):
        def __init__(self, data, segment, addr, disp = 0,
                dataSize="env.dataSize", addressSize="env.addressSize"):
            super(LeaOp, self).__init__(data, segment, addr, disp,
                    dataSize, addressSize, "0",
                    False, False, False, False, False)
            self.className = "Lea"
            self.mnemonic = "lea"

    microopClasses["lea"] = LeaOp


    iop = InstObjParams("tia", "Tia", 'X86ISA::LdStOp',
                        { "code": "xc->demapPage(EA, 0);",
                          "ea_code": calculateEA,
                          "memDataSize": "dataSize" })
    header_output += MicroLeaDeclare.subst(iop)
    decoder_output += MicroLdStOpConstructor.subst(iop)
    exec_output += MicroLeaExecute.subst(iop)

    class TiaOp(LdStOp):
        def __init__(self, segment, addr, disp = 0,
                dataSize="env.dataSize",
                addressSize="env.addressSize"):
            super(TiaOp, self).__init__("InstRegIndex(NUM_INTREGS)", segment,
                    addr, disp, dataSize, addressSize, "0", False, False,
                    False, False, False)
            self.className = "Tia"
            self.mnemonic = "tia"

    microopClasses["tia"] = TiaOp

    class CdaOp(LdStOp):
        def __init__(self, segment, addr, disp = 0,
                dataSize="env.dataSize",
                addressSize="env.addressSize", atCPL0=False):
            super(CdaOp, self).__init__("InstRegIndex(NUM_INTREGS)", segment,
                    addr, disp, dataSize, addressSize, "Request::NO_ACCESS",
                    atCPL0, False, False, False, False)
            self.className = "Cda"
            self.mnemonic = "cda"

    microopClasses["cda"] = CdaOp
}};