| // -*- mode:c++ -*- |
| |
| // Copyright (c) 2011-2013,2017 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 {{ |
| |
| header_output = "" |
| decoder_output = "" |
| exec_output = "" |
| |
| class StoreInst64(LoadStoreInst): |
| execBase = 'Store64' |
| micro = False |
| |
| def __init__(self, mnem, Name, size=4, user=False, flavor="normal", |
| top = False): |
| super(StoreInst64, self).__init__() |
| |
| self.name = mnem |
| self.Name = Name |
| self.size = size |
| self.user = user |
| self.flavor = flavor |
| self.top = top |
| |
| self.memFlags = ["ArmISA::TLB::MustBeOne"] |
| self.instFlags = [] |
| self.codeBlobs = { "postacc_code" : "" } |
| |
| # Add memory request flags where necessary |
| if self.user: |
| self.memFlags.append("ArmISA::TLB::UserMode") |
| |
| if self.flavor in ("relexp", "exp"): |
| # For exclusive pair ops alignment check is based on total size |
| self.memFlags.append("%d" % int(math.log(self.size, 2) + 1)) |
| elif not (self.size == 16 and self.top): |
| # Only the first microop should perform alignment checking. |
| self.memFlags.append("%d" % int(math.log(self.size, 2))) |
| |
| if self.flavor not in ("release", "relex", "exclusive", |
| "relexp", "exp"): |
| self.memFlags.append("ArmISA::TLB::AllowUnaligned") |
| |
| if self.micro: |
| self.instFlags.append("IsMicroop") |
| |
| if self.flavor in ("release", "relex", "relexp"): |
| self.instFlags.extend(["IsMemBarrier", |
| "IsWriteBarrier", |
| "IsReadBarrier"]) |
| if self.flavor in ("relex", "exclusive", "exp", "relexp"): |
| self.instFlags.append("IsStoreConditional") |
| self.memFlags.append("Request::LLSC") |
| |
| def emitHelper(self, base = 'Memory64', wbDecl = None): |
| global header_output, decoder_output, exec_output |
| |
| # If this is a microop itself, don't allow anything that would |
| # require further microcoding. |
| if self.micro: |
| assert not wbDecl |
| |
| fa_code = None |
| if not self.micro and self.flavor in ("normal", "release"): |
| fa_code = ''' |
| fault->annotate(ArmFault::SAS, %s); |
| fault->annotate(ArmFault::SSE, false); |
| fault->annotate(ArmFault::SRT, dest); |
| fault->annotate(ArmFault::SF, %s); |
| fault->annotate(ArmFault::AR, %s); |
| ''' % ("0" if self.size == 1 else |
| "1" if self.size == 2 else |
| "2" if self.size == 4 else "3", |
| "true" if self.size == 8 else "false", |
| "true" if self.flavor == "release" else "false") |
| |
| (newHeader, newDecoder, newExec) = \ |
| self.fillTemplates(self.name, self.Name, self.codeBlobs, |
| self.memFlags, self.instFlags, |
| base, wbDecl, faCode=fa_code) |
| |
| header_output += newHeader |
| decoder_output += newDecoder |
| exec_output += newExec |
| |
| def buildEACode(self): |
| # Address computation |
| eaCode = "" |
| if self.flavor == "fp": |
| eaCode += vfp64EnabledCheckCode |
| |
| eaCode += SPAlignmentCheckCode + "EA = XBase" |
| if self.size == 16: |
| if self.top: |
| eaCode += " + (isBigEndian64(xc->tcBase()) ? 0 : 8)" |
| else: |
| eaCode += " + (isBigEndian64(xc->tcBase()) ? 8 : 0)" |
| if not self.post: |
| eaCode += self.offset |
| eaCode += ";" |
| |
| self.codeBlobs["ea_code"] = eaCode |
| |
| |
| class StoreImmInst64(StoreInst64): |
| def __init__(self, *args, **kargs): |
| super(StoreImmInst64, self).__init__(*args, **kargs) |
| self.offset = "+ imm" |
| |
| self.wbDecl = "MicroAddXiUop(machInst, base, base, imm);" |
| |
| class StoreRegInst64(StoreInst64): |
| def __init__(self, *args, **kargs): |
| super(StoreRegInst64, self).__init__(*args, **kargs) |
| self.offset = "+ extendReg64(XOffset, type, shiftAmt, 64)" |
| |
| self.wbDecl = \ |
| "MicroAddXERegUop(machInst, base, base, " + \ |
| " offset, type, shiftAmt);" |
| |
| class StoreRawRegInst64(StoreInst64): |
| def __init__(self, *args, **kargs): |
| super(StoreRawRegInst64, self).__init__(*args, **kargs) |
| self.offset = "" |
| |
| class StoreSingle64(StoreInst64): |
| def emit(self): |
| self.buildEACode() |
| |
| # Code that actually handles the access |
| if self.flavor == "fp": |
| if self.size in (1, 2, 4): |
| accCode = ''' |
| Mem%(suffix)s = |
| cSwap(AA64FpDestP0%(suffix)s, isBigEndian64(xc->tcBase())); |
| ''' |
| elif self.size == 8 or (self.size == 16 and not self.top): |
| accCode = ''' |
| uint64_t data = AA64FpDestP1_uw; |
| data = (data << 32) | AA64FpDestP0_uw; |
| Mem%(suffix)s = cSwap(data, isBigEndian64(xc->tcBase())); |
| ''' |
| elif self.size == 16 and self.top: |
| accCode = ''' |
| uint64_t data = AA64FpDestP3_uw; |
| data = (data << 32) | AA64FpDestP2_uw; |
| Mem%(suffix)s = cSwap(data, isBigEndian64(xc->tcBase())); |
| ''' |
| else: |
| accCode = \ |
| 'Mem%(suffix)s = cSwap(XDest%(suffix)s, isBigEndian64(xc->tcBase()));' |
| if self.size == 16: |
| accCode = accCode % \ |
| { "suffix" : buildMemSuffix(False, 8) } |
| else: |
| accCode = accCode % \ |
| { "suffix" : buildMemSuffix(False, self.size) } |
| |
| self.codeBlobs["memacc_code"] = accCode |
| |
| if self.flavor in ("relex", "exclusive"): |
| self.instFlags.append("IsStoreConditional") |
| self.memFlags.append("Request::LLSC") |
| |
| # Push it out to the output files |
| wbDecl = None |
| if self.writeback and not self.micro: |
| wbDecl = self.wbDecl |
| self.emitHelper(self.base, wbDecl) |
| |
| class StoreDouble64(StoreInst64): |
| def emit(self): |
| self.buildEACode() |
| |
| # Code that actually handles the access |
| if self.flavor == "fp": |
| accCode = ''' |
| uint64_t data = AA64FpDest2P0_uw; |
| data = isBigEndian64(xc->tcBase()) |
| ? ((uint64_t(AA64FpDestP0_uw) << 32) | data) |
| : ((data << 32) | AA64FpDestP0_uw); |
| Mem_ud = cSwap(data, isBigEndian64(xc->tcBase())); |
| ''' |
| else: |
| if self.size == 4: |
| accCode = ''' |
| uint64_t data = XDest2_uw; |
| data = isBigEndian64(xc->tcBase()) |
| ? ((uint64_t(XDest_uw) << 32) | data) |
| : ((data << 32) | XDest_uw); |
| Mem_ud = cSwap(data, isBigEndian64(xc->tcBase())); |
| ''' |
| elif self.size == 8: |
| accCode = ''' |
| // This temporary needs to be here so that the parser |
| // will correctly identify this instruction as a store. |
| std::array<uint64_t, 2> temp; |
| temp[0] = cSwap(XDest_ud,isBigEndian64(xc->tcBase())); |
| temp[1] = cSwap(XDest2_ud,isBigEndian64(xc->tcBase())); |
| Mem_tud = temp; |
| ''' |
| self.codeBlobs["memacc_code"] = accCode |
| |
| # Push it out to the output files |
| wbDecl = None |
| if self.writeback and not self.micro: |
| wbDecl = self.wbDecl |
| self.emitHelper(self.base, wbDecl) |
| |
| class StoreImm64(StoreImmInst64, StoreSingle64): |
| decConstBase = 'LoadStoreImm64' |
| base = 'ArmISA::MemoryImm64' |
| writeback = False |
| post = False |
| |
| class StorePre64(StoreImmInst64, StoreSingle64): |
| decConstBase = 'LoadStoreImm64' |
| base = 'ArmISA::MemoryPreIndex64' |
| writeback = True |
| post = False |
| |
| class StorePost64(StoreImmInst64, StoreSingle64): |
| decConstBase = 'LoadStoreImm64' |
| base = 'ArmISA::MemoryPostIndex64' |
| writeback = True |
| post = True |
| |
| class StoreReg64(StoreRegInst64, StoreSingle64): |
| decConstBase = 'LoadStoreReg64' |
| base = 'ArmISA::MemoryReg64' |
| writeback = False |
| post = False |
| |
| class StoreRaw64(StoreRawRegInst64, StoreSingle64): |
| decConstBase = 'LoadStoreRaw64' |
| base = 'ArmISA::MemoryRaw64' |
| writeback = False |
| post = False |
| |
| class StoreEx64(StoreRawRegInst64, StoreSingle64): |
| decConstBase = 'LoadStoreEx64' |
| base = 'ArmISA::MemoryEx64' |
| writeback = False |
| post = False |
| execBase = 'StoreEx64' |
| def __init__(self, *args, **kargs): |
| super(StoreEx64, self).__init__(*args, **kargs) |
| self.codeBlobs["postacc_code"] = \ |
| "XResult = !writeResult; SevMailbox = 1; LLSCLock = 0;" |
| |
| def buildStores64(mnem, NameBase, size, flavor="normal"): |
| StoreImm64(mnem, NameBase + "_IMM", size, flavor=flavor).emit() |
| StorePre64(mnem, NameBase + "_PRE", size, flavor=flavor).emit() |
| StorePost64(mnem, NameBase + "_POST", size, flavor=flavor).emit() |
| StoreReg64(mnem, NameBase + "_REG", size, flavor=flavor).emit() |
| |
| buildStores64("strb", "STRB64", 1) |
| buildStores64("strh", "STRH64", 2) |
| buildStores64("str", "STRW64", 4) |
| buildStores64("str", "STRX64", 8) |
| buildStores64("str", "STRBFP64", 1, flavor="fp") |
| buildStores64("str", "STRHFP64", 2, flavor="fp") |
| buildStores64("str", "STRSFP64", 4, flavor="fp") |
| buildStores64("str", "STRDFP64", 8, flavor="fp") |
| |
| StoreImm64("sturb", "STURB64_IMM", 1).emit() |
| StoreImm64("sturh", "STURH64_IMM", 2).emit() |
| StoreImm64("stur", "STURW64_IMM", 4).emit() |
| StoreImm64("stur", "STURX64_IMM", 8).emit() |
| StoreImm64("stur", "STURBFP64_IMM", 1, flavor="fp").emit() |
| StoreImm64("stur", "STURHFP64_IMM", 2, flavor="fp").emit() |
| StoreImm64("stur", "STURSFP64_IMM", 4, flavor="fp").emit() |
| StoreImm64("stur", "STURDFP64_IMM", 8, flavor="fp").emit() |
| |
| StoreImm64("sttrb", "STTRB64_IMM", 1, user=True).emit() |
| StoreImm64("sttrh", "STTRH64_IMM", 2, user=True).emit() |
| StoreImm64("sttr", "STTRW64_IMM", 4, user=True).emit() |
| StoreImm64("sttr", "STTRX64_IMM", 8, user=True).emit() |
| |
| StoreRaw64("stlr", "STLRX64", 8, flavor="release").emit() |
| StoreRaw64("stlr", "STLRW64", 4, flavor="release").emit() |
| StoreRaw64("stlrh", "STLRH64", 2, flavor="release").emit() |
| StoreRaw64("stlrb", "STLRB64", 1, flavor="release").emit() |
| |
| StoreEx64("stlxr", "STLXRX64", 8, flavor="relex").emit() |
| StoreEx64("stlxr", "STLXRW64", 4, flavor="relex").emit() |
| StoreEx64("stlxrh", "STLXRH64", 2, flavor="relex").emit() |
| StoreEx64("stlxrb", "STLXRB64", 1, flavor="relex").emit() |
| |
| StoreEx64("stxr", "STXRX64", 8, flavor="exclusive").emit() |
| StoreEx64("stxr", "STXRW64", 4, flavor="exclusive").emit() |
| StoreEx64("stxrh", "STXRH64", 2, flavor="exclusive").emit() |
| StoreEx64("stxrb", "STXRB64", 1, flavor="exclusive").emit() |
| |
| class StoreImmU64(StoreImm64): |
| decConstBase = 'LoadStoreImmU64' |
| micro = True |
| |
| class StoreImmDU64(StoreImmInst64, StoreDouble64): |
| decConstBase = 'LoadStoreImmDU64' |
| base = 'ArmISA::MemoryDImm64' |
| micro = True |
| post = False |
| writeback = False |
| |
| class StoreImmDEx64(StoreImmInst64, StoreDouble64): |
| execBase = 'StoreEx64' |
| decConstBase = 'StoreImmDEx64' |
| base = 'ArmISA::MemoryDImmEx64' |
| micro = False |
| post = False |
| writeback = False |
| def __init__(self, *args, **kargs): |
| super(StoreImmDEx64, self).__init__(*args, **kargs) |
| self.codeBlobs["postacc_code"] = \ |
| "XResult = !writeResult; SevMailbox = 1; LLSCLock = 0;" |
| |
| class StoreRegU64(StoreReg64): |
| decConstBase = 'LoadStoreRegU64' |
| micro = True |
| |
| StoreImmDEx64("stlxp", "STLXPW64", 4, flavor="relexp").emit() |
| StoreImmDEx64("stlxp", "STLXPX64", 8, flavor="relexp").emit() |
| StoreImmDEx64("stxp", "STXPW64", 4, flavor="exp").emit() |
| StoreImmDEx64("stxp", "STXPX64", 8, flavor="exp").emit() |
| |
| StoreImmU64("strxi_uop", "MicroStrXImmUop", 8).emit() |
| StoreRegU64("strxr_uop", "MicroStrXRegUop", 8).emit() |
| StoreImmU64("strfpxi_uop", "MicroStrFpXImmUop", 8, flavor="fp").emit() |
| StoreRegU64("strfpxr_uop", "MicroStrFpXRegUop", 8, flavor="fp").emit() |
| StoreImmU64("strqbfpxi_uop", "MicroStrQBFpXImmUop", |
| 16, flavor="fp", top=False).emit() |
| StoreRegU64("strqbfpxr_uop", "MicroStrQBFpXRegUop", |
| 16, flavor="fp", top=False).emit() |
| StoreImmU64("strqtfpxi_uop", "MicroStrQTFpXImmUop", |
| 16, flavor="fp", top=True).emit() |
| StoreRegU64("strqtfpxr_uop", "MicroStrQTFpXRegUop", |
| 16, flavor="fp", top=True).emit() |
| StoreImmDU64("strdxi_uop", "MicroStrDXImmUop", 4).emit() |
| StoreImmDU64("strdfpxi_uop", "MicroStrDFpXImmUop", 4, flavor="fp").emit() |
| |
| }}; |