| // -*- mode:c++ -*- |
| |
| // Copyright (c) 2010-2014 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. |
| // |
| // Copyright (c) 2007-2008 The Florida State University |
| // 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: Stephen Hines |
| // Gabe Black |
| |
| //////////////////////////////////////////////////////////////////// |
| // |
| // Load/store microops |
| // |
| |
| let {{ |
| microLdrUopCode = "IWRa = cSwap(Mem_uw, ((CPSR)Cpsr).e);" |
| microLdrUopIop = InstObjParams('ldr_uop', 'MicroLdrUop', |
| 'MicroMemOp', |
| {'memacc_code': microLdrUopCode, |
| 'ea_code': 'EA = URb + (up ? imm : -imm);', |
| 'predicate_test': predicateTest}, |
| ['IsMicroop']) |
| |
| microLdr2UopCode = ''' |
| uint64_t data = Mem_ud; |
| Dest = cSwap((uint32_t) data, ((CPSR)Cpsr).e); |
| IWDest2 = cSwap((uint32_t) (data >> 32), |
| ((CPSR)Cpsr).e); |
| ''' |
| microLdr2UopIop = InstObjParams('ldr2_uop', 'MicroLdr2Uop', |
| 'MicroMemPairOp', |
| {'memacc_code': microLdr2UopCode, |
| 'ea_code': 'EA = URb + (up ? imm : -imm);', |
| 'predicate_test': predicateTest}, |
| ['IsMicroop']) |
| |
| microLdrFpUopCode = "Fa_uw = cSwap(Mem_uw, ((CPSR)Cpsr).e);" |
| microLdrFpUopIop = InstObjParams('ldrfp_uop', 'MicroLdrFpUop', |
| 'MicroMemOp', |
| {'memacc_code': microLdrFpUopCode, |
| 'ea_code': vfpEnabledCheckCode + |
| 'EA = URb + (up ? imm : -imm);', |
| 'predicate_test': predicateTest}, |
| ['IsMicroop']) |
| |
| microLdrDBFpUopCode = "Fa_uw = cSwap(Mem_uw, ((CPSR)Cpsr).e);" |
| microLdrDBFpUopIop = InstObjParams('ldrfp_uop', 'MicroLdrDBFpUop', |
| 'MicroMemOp', |
| {'memacc_code': microLdrFpUopCode, |
| 'ea_code': vfpEnabledCheckCode + ''' |
| EA = URb + (up ? imm : -imm) + |
| (((CPSR)Cpsr).e ? 4 : 0); |
| ''', |
| 'predicate_test': predicateTest}, |
| ['IsMicroop']) |
| |
| microLdrDTFpUopCode = "Fa_uw = cSwap(Mem_uw, ((CPSR)Cpsr).e);" |
| microLdrDTFpUopIop = InstObjParams('ldrfp_uop', 'MicroLdrDTFpUop', |
| 'MicroMemOp', |
| {'memacc_code': microLdrFpUopCode, |
| 'ea_code': vfpEnabledCheckCode + ''' |
| EA = URb + (up ? imm : -imm) - |
| (((CPSR)Cpsr).e ? 4 : 0); |
| ''', |
| 'predicate_test': predicateTest}, |
| ['IsMicroop']) |
| |
| microRetUopCode = ''' |
| CPSR old_cpsr = Cpsr; |
| SCTLR sctlr = Sctlr; |
| |
| CPSR new_cpsr = |
| cpsrWriteByInstr(old_cpsr, Spsr, Scr, Nsacr, 0xF, true, |
| sctlr.nmfi, xc->tcBase()); |
| Cpsr = ~CondCodesMask & new_cpsr; |
| CondCodesNZ = new_cpsr.nz; |
| CondCodesC = new_cpsr.c; |
| CondCodesV = new_cpsr.v; |
| CondCodesGE = new_cpsr.ge; |
| IWNPC = cSwap(%s, old_cpsr.e) | ((Spsr & 0x20) ? 1 : 0); |
| NextItState = ((((CPSR)Spsr).it2 << 2) & 0xFC) |
| | (((CPSR)Spsr).it1 & 0x3); |
| SevMailbox = 1; |
| ''' |
| |
| microLdrRetUopIop = InstObjParams('ldr_ret_uop', 'MicroLdrRetUop', |
| 'MicroMemOp', |
| {'memacc_code': |
| microRetUopCode % 'Mem_uw', |
| 'ea_code': |
| 'EA = URb + (up ? imm : -imm);', |
| 'predicate_test': condPredicateTest}, |
| ['IsMicroop','IsNonSpeculative', |
| 'IsSerializeAfter', 'IsSquashAfter']) |
| |
| microStrUopCode = "Mem = cSwap(URa_uw, ((CPSR)Cpsr).e);" |
| microStrUopIop = InstObjParams('str_uop', 'MicroStrUop', |
| 'MicroMemOp', |
| {'memacc_code': microStrUopCode, |
| 'postacc_code': "", |
| 'ea_code': 'EA = URb + (up ? imm : -imm);', |
| 'predicate_test': predicateTest}, |
| ['IsMicroop']) |
| |
| microStrFpUopCode = "Mem = cSwap(Fa_uw, ((CPSR)Cpsr).e);" |
| microStrFpUopIop = InstObjParams('strfp_uop', 'MicroStrFpUop', |
| 'MicroMemOp', |
| {'memacc_code': microStrFpUopCode, |
| 'postacc_code': "", |
| 'ea_code': vfpEnabledCheckCode + |
| 'EA = URb + (up ? imm : -imm);', |
| 'predicate_test': predicateTest}, |
| ['IsMicroop']) |
| |
| microStrDBFpUopCode = "Mem = cSwap(Fa_uw, ((CPSR)Cpsr).e);" |
| microStrDBFpUopIop = InstObjParams('strfp_uop', 'MicroStrDBFpUop', |
| 'MicroMemOp', |
| {'memacc_code': microStrFpUopCode, |
| 'postacc_code': "", |
| 'ea_code': vfpEnabledCheckCode + ''' |
| EA = URb + (up ? imm : -imm) + |
| (((CPSR)Cpsr).e ? 4 : 0); |
| ''', |
| 'predicate_test': predicateTest}, |
| ['IsMicroop']) |
| |
| microStrDTFpUopCode = "Mem = cSwap(Fa_uw, ((CPSR)Cpsr).e);" |
| microStrDTFpUopIop = InstObjParams('strfp_uop', 'MicroStrDTFpUop', |
| 'MicroMemOp', |
| {'memacc_code': microStrFpUopCode, |
| 'postacc_code': "", |
| 'ea_code': vfpEnabledCheckCode + ''' |
| EA = URb + (up ? imm : -imm) - |
| (((CPSR)Cpsr).e ? 4 : 0); |
| ''', |
| 'predicate_test': predicateTest}, |
| ['IsMicroop']) |
| |
| header_output = decoder_output = exec_output = '' |
| |
| loadIops = (microLdrUopIop, microLdrRetUopIop, |
| microLdrFpUopIop, microLdrDBFpUopIop, microLdrDTFpUopIop) |
| storeIops = (microStrUopIop, microStrFpUopIop, |
| microStrDBFpUopIop, microStrDTFpUopIop) |
| for iop in loadIops + storeIops: |
| header_output += MicroMemDeclare.subst(iop) |
| decoder_output += MicroMemConstructor.subst(iop) |
| for iop in loadIops: |
| exec_output += LoadExecute.subst(iop) + \ |
| LoadInitiateAcc.subst(iop) + \ |
| LoadCompleteAcc.subst(iop) |
| for iop in storeIops: |
| exec_output += StoreExecute.subst(iop) + \ |
| StoreInitiateAcc.subst(iop) + \ |
| StoreCompleteAcc.subst(iop) |
| |
| header_output += MicroMemPairDeclare.subst(microLdr2UopIop) |
| decoder_output += MicroMemPairConstructor.subst(microLdr2UopIop) |
| exec_output += LoadExecute.subst(microLdr2UopIop) + \ |
| LoadInitiateAcc.subst(microLdr2UopIop) + \ |
| LoadCompleteAcc.subst(microLdr2UopIop) |
| }}; |
| |
| let {{ |
| exec_output = header_output = '' |
| |
| eaCode = 'EA = XURa + imm;' |
| |
| for size in (1, 2, 3, 4, 6, 8, 12, 16): |
| # Set up the memory access. |
| regs = (size + 3) // 4 |
| subst = { "size" : size, "regs" : regs } |
| memDecl = ''' |
| union MemUnion { |
| uint8_t bytes[%(size)d]; |
| Element elements[%(size)d / sizeof(Element)]; |
| uint32_t floatRegBits[%(regs)d]; |
| }; |
| ''' % subst |
| |
| # Do endian conversion for all the elements. |
| convCode = ''' |
| const unsigned eCount = sizeof(memUnion.elements) / |
| sizeof(memUnion.elements[0]); |
| if (((CPSR)Cpsr).e) { |
| for (unsigned i = 0; i < eCount; i++) { |
| memUnion.elements[i] = gtobe(memUnion.elements[i]); |
| } |
| } else { |
| for (unsigned i = 0; i < eCount; i++) { |
| memUnion.elements[i] = gtole(memUnion.elements[i]); |
| } |
| } |
| ''' |
| |
| # Offload everything into registers |
| regSetCode = '' |
| for reg in range(regs): |
| mask = '' |
| if reg == regs - 1: |
| mask = ' & mask(%d)' % (32 - 8 * (regs * 4 - size)) |
| regSetCode += ''' |
| FpDestP%(reg)d_uw = gtoh(memUnion.floatRegBits[%(reg)d])%(mask)s; |
| ''' % { "reg" : reg, "mask" : mask } |
| |
| # Pull everything in from registers |
| regGetCode = '' |
| for reg in range(regs): |
| regGetCode += ''' |
| memUnion.floatRegBits[%(reg)d] = htog(FpDestP%(reg)d_uw); |
| ''' % { "reg" : reg } |
| |
| loadMemAccCode = convCode + regSetCode |
| storeMemAccCode = regGetCode + convCode |
| |
| loadIop = InstObjParams('ldrneon%(size)d_uop' % subst, |
| 'MicroLdrNeon%(size)dUop' % subst, |
| 'MicroNeonMemOp', |
| { 'mem_decl' : memDecl, |
| 'size' : size, |
| 'memacc_code' : loadMemAccCode, |
| 'ea_code' : simdEnabledCheckCode + eaCode, |
| 'predicate_test' : predicateTest }, |
| [ 'IsMicroop', 'IsMemRef', 'IsLoad' ]) |
| storeIop = InstObjParams('strneon%(size)d_uop' % subst, |
| 'MicroStrNeon%(size)dUop' % subst, |
| 'MicroNeonMemOp', |
| { 'mem_decl' : memDecl, |
| 'size' : size, |
| 'memacc_code' : storeMemAccCode, |
| 'ea_code' : simdEnabledCheckCode + eaCode, |
| 'predicate_test' : predicateTest }, |
| [ 'IsMicroop', 'IsMemRef', 'IsStore' ]) |
| |
| exec_output += NeonLoadExecute.subst(loadIop) + \ |
| NeonLoadInitiateAcc.subst(loadIop) + \ |
| NeonLoadCompleteAcc.subst(loadIop) + \ |
| NeonStoreExecute.subst(storeIop) + \ |
| NeonStoreInitiateAcc.subst(storeIop) + \ |
| NeonStoreCompleteAcc.subst(storeIop) |
| header_output += MicroNeonMemDeclare.subst(loadIop) + \ |
| MicroNeonMemDeclare.subst(storeIop) |
| }}; |
| |
| let {{ |
| exec_output = '' |
| for eSize, type in (1, 'uint8_t'), \ |
| (2, 'uint16_t'), \ |
| (4, 'uint32_t'), \ |
| (8, 'uint64_t'): |
| size = eSize |
| # An instruction handles no more than 16 bytes and no more than |
| # 4 elements, or the number of elements needed to fill 8 or 16 bytes. |
| sizes = set((16, 8)) |
| for count in 1, 2, 3, 4: |
| size = count * eSize |
| if size <= 16: |
| sizes.add(size) |
| for size in sizes: |
| substDict = { |
| "class_name" : "MicroLdrNeon%dUop" % size, |
| "targs" : type |
| } |
| exec_output += MicroNeonMemExecDeclare.subst(substDict) |
| substDict["class_name"] = "MicroStrNeon%dUop" % size |
| exec_output += MicroNeonMemExecDeclare.subst(substDict) |
| size += eSize |
| }}; |
| |
| //////////////////////////////////////////////////////////////////// |
| // |
| // Neon (de)interlacing microops |
| // |
| |
| let {{ |
| header_output = exec_output = '' |
| for dRegs in (2, 3, 4): |
| loadConv = '' |
| unloadConv = '' |
| for dReg in range(dRegs): |
| loadConv += ''' |
| conv1.cRegs[%(sReg0)d] = htog(FpOp1P%(sReg0)d_uw); |
| conv1.cRegs[%(sReg1)d] = htog(FpOp1P%(sReg1)d_uw); |
| ''' % { "sReg0" : (dReg * 2), "sReg1" : (dReg * 2 + 1) } |
| unloadConv += ''' |
| FpDestS%(dReg)dP0_uw = gtoh(conv2.cRegs[2 * %(dReg)d + 0]); |
| FpDestS%(dReg)dP1_uw = gtoh(conv2.cRegs[2 * %(dReg)d + 1]); |
| ''' % { "dReg" : dReg } |
| microDeintNeonCode = ''' |
| const unsigned dRegs = %(dRegs)d; |
| const unsigned regs = 2 * dRegs; |
| const unsigned perDReg = |
| (2 * sizeof(uint32_t)) / sizeof(Element); |
| union convStruct { |
| uint32_t cRegs[regs]; |
| Element elements[dRegs * perDReg]; |
| } conv1, conv2; |
| |
| %(loadConv)s |
| |
| unsigned srcElem = 0; |
| for (unsigned destOffset = 0; |
| destOffset < perDReg; destOffset++) { |
| for (unsigned dReg = 0; dReg < dRegs; dReg++) { |
| conv2.elements[dReg * perDReg + destOffset] = |
| conv1.elements[srcElem++]; |
| } |
| } |
| |
| %(unloadConv)s |
| ''' % { "dRegs" : dRegs, |
| "loadConv" : loadConv, |
| "unloadConv" : unloadConv } |
| microDeintNeonIop = \ |
| InstObjParams('deintneon%duop' % (dRegs * 2), |
| 'MicroDeintNeon%dUop' % (dRegs * 2), |
| 'MicroNeonMixOp', |
| { 'predicate_test': predicateTest, |
| 'code' : microDeintNeonCode }, |
| ['IsMicroop']) |
| header_output += MicroNeonMixDeclare.subst(microDeintNeonIop) |
| exec_output += MicroNeonMixExecute.subst(microDeintNeonIop) |
| |
| loadConv = '' |
| unloadConv = '' |
| for dReg in range(dRegs): |
| loadConv += ''' |
| conv1.cRegs[2 * %(dReg)d + 0] = htog(FpOp1S%(dReg)dP0_uw); |
| conv1.cRegs[2 * %(dReg)d + 1] = htog(FpOp1S%(dReg)dP1_uw); |
| ''' % { "dReg" : dReg } |
| unloadConv += ''' |
| FpDestP%(sReg0)d_uw = gtoh(conv2.cRegs[%(sReg0)d]); |
| FpDestP%(sReg1)d_uw = gtoh(conv2.cRegs[%(sReg1)d]); |
| ''' % { "sReg0" : (dReg * 2), "sReg1" : (dReg * 2 + 1) } |
| microInterNeonCode = ''' |
| const unsigned dRegs = %(dRegs)d; |
| const unsigned regs = 2 * dRegs; |
| const unsigned perDReg = |
| (2 * sizeof(uint32_t)) / sizeof(Element); |
| union convStruct { |
| uint32_t cRegs[regs]; |
| Element elements[dRegs * perDReg]; |
| } conv1, conv2; |
| |
| %(loadConv)s |
| |
| unsigned destElem = 0; |
| for (unsigned srcOffset = 0; |
| srcOffset < perDReg; srcOffset++) { |
| for (unsigned dReg = 0; dReg < dRegs; dReg++) { |
| conv2.elements[destElem++] = |
| conv1.elements[dReg * perDReg + srcOffset]; |
| } |
| } |
| |
| %(unloadConv)s |
| ''' % { "dRegs" : dRegs, |
| "loadConv" : loadConv, |
| "unloadConv" : unloadConv } |
| microInterNeonIop = \ |
| InstObjParams('interneon%duop' % (dRegs * 2), |
| 'MicroInterNeon%dUop' % (dRegs * 2), |
| 'MicroNeonMixOp', |
| { 'predicate_test': predicateTest, |
| 'code' : microInterNeonCode }, |
| ['IsMicroop']) |
| header_output += MicroNeonMixDeclare.subst(microInterNeonIop) |
| exec_output += MicroNeonMixExecute.subst(microInterNeonIop) |
| }}; |
| |
| let {{ |
| exec_output = '' |
| for type in ('uint8_t', 'uint16_t', 'uint32_t', 'uint64_t'): |
| for dRegs in (2, 3, 4): |
| Name = "MicroDeintNeon%dUop" % (dRegs * 2) |
| substDict = { "class_name" : Name, "targs" : type } |
| exec_output += MicroNeonExecDeclare.subst(substDict) |
| Name = "MicroInterNeon%dUop" % (dRegs * 2) |
| substDict = { "class_name" : Name, "targs" : type } |
| exec_output += MicroNeonExecDeclare.subst(substDict) |
| }}; |
| |
| //////////////////////////////////////////////////////////////////// |
| // |
| // Neon microops to pack/unpack a single lane |
| // |
| |
| let {{ |
| header_output = exec_output = '' |
| for sRegs in 1, 2: |
| baseLoadRegs = '' |
| for reg in range(sRegs): |
| baseLoadRegs += ''' |
| sourceRegs.fRegs[%(reg0)d] = htog(FpOp1P%(reg0)d_uw); |
| sourceRegs.fRegs[%(reg1)d] = htog(FpOp1P%(reg1)d_uw); |
| ''' % { "reg0" : (2 * reg + 0), |
| "reg1" : (2 * reg + 1) } |
| for dRegs in range(sRegs, 5): |
| unloadRegs = '' |
| loadRegs = baseLoadRegs |
| for reg in range(dRegs): |
| loadRegs += ''' |
| destRegs[%(reg)d].fRegs[0] = htog(FpDestS%(reg)dP0_uw); |
| destRegs[%(reg)d].fRegs[1] = htog(FpDestS%(reg)dP1_uw); |
| ''' % { "reg" : reg } |
| unloadRegs += ''' |
| FpDestS%(reg)dP0_uw = gtoh(destRegs[%(reg)d].fRegs[0]); |
| FpDestS%(reg)dP1_uw = gtoh(destRegs[%(reg)d].fRegs[1]); |
| ''' % { "reg" : reg } |
| microUnpackNeonCode = ''' |
| const unsigned perDReg = (2 * sizeof(uint32_t)) / sizeof(Element); |
| |
| union SourceRegs { |
| uint32_t fRegs[2 * %(sRegs)d]; |
| Element elements[%(sRegs)d * perDReg]; |
| } sourceRegs; |
| |
| union DestReg { |
| uint32_t fRegs[2]; |
| Element elements[perDReg]; |
| } destRegs[%(dRegs)d]; |
| |
| %(loadRegs)s |
| |
| for (unsigned i = 0; i < %(dRegs)d; i++) { |
| destRegs[i].elements[lane] = sourceRegs.elements[i]; |
| } |
| |
| %(unloadRegs)s |
| ''' % { "sRegs" : sRegs, "dRegs" : dRegs, |
| "loadRegs" : loadRegs, "unloadRegs" : unloadRegs } |
| |
| microUnpackNeonIop = \ |
| InstObjParams('unpackneon%dto%duop' % (sRegs * 2, dRegs * 2), |
| 'MicroUnpackNeon%dto%dUop' % |
| (sRegs * 2, dRegs * 2), |
| 'MicroNeonMixLaneOp', |
| { 'predicate_test': predicateTest, |
| 'code' : microUnpackNeonCode }, |
| ['IsMicroop']) |
| header_output += MicroNeonMixLaneDeclare.subst(microUnpackNeonIop) |
| exec_output += MicroNeonMixExecute.subst(microUnpackNeonIop) |
| |
| for sRegs in 1, 2: |
| loadRegs = '' |
| for reg in range(sRegs): |
| loadRegs += ''' |
| sourceRegs.fRegs[%(reg0)d] = htog(FpOp1P%(reg0)d_uw); |
| sourceRegs.fRegs[%(reg1)d] = htog(FpOp1P%(reg1)d_uw); |
| ''' % { "reg0" : (2 * reg + 0), |
| "reg1" : (2 * reg + 1) } |
| for dRegs in range(sRegs, 5): |
| unloadRegs = '' |
| for reg in range(dRegs): |
| unloadRegs += ''' |
| FpDestS%(reg)dP0_uw = gtoh(destRegs[%(reg)d].fRegs[0]); |
| FpDestS%(reg)dP1_uw = gtoh(destRegs[%(reg)d].fRegs[1]); |
| ''' % { "reg" : reg } |
| microUnpackAllNeonCode = ''' |
| const unsigned perDReg = (2 * sizeof(uint32_t)) / sizeof(Element); |
| |
| union SourceRegs { |
| uint32_t fRegs[2 * %(sRegs)d]; |
| Element elements[%(sRegs)d * perDReg]; |
| } sourceRegs; |
| |
| union DestReg { |
| uint32_t fRegs[2]; |
| Element elements[perDReg]; |
| } destRegs[%(dRegs)d]; |
| |
| %(loadRegs)s |
| |
| for (unsigned i = 0; i < %(dRegs)d; i++) { |
| for (unsigned j = 0; j < perDReg; j++) |
| destRegs[i].elements[j] = sourceRegs.elements[i]; |
| } |
| |
| %(unloadRegs)s |
| ''' % { "sRegs" : sRegs, "dRegs" : dRegs, |
| "loadRegs" : loadRegs, "unloadRegs" : unloadRegs } |
| |
| microUnpackAllNeonIop = \ |
| InstObjParams('unpackallneon%dto%duop' % (sRegs * 2, dRegs * 2), |
| 'MicroUnpackAllNeon%dto%dUop' % |
| (sRegs * 2, dRegs * 2), |
| 'MicroNeonMixOp', |
| { 'predicate_test': predicateTest, |
| 'code' : microUnpackAllNeonCode }, |
| ['IsMicroop']) |
| header_output += MicroNeonMixDeclare.subst(microUnpackAllNeonIop) |
| exec_output += MicroNeonMixExecute.subst(microUnpackAllNeonIop) |
| |
| for dRegs in 1, 2: |
| unloadRegs = '' |
| for reg in range(dRegs): |
| unloadRegs += ''' |
| FpDestP%(reg0)d_uw = gtoh(destRegs.fRegs[%(reg0)d]); |
| FpDestP%(reg1)d_uw = gtoh(destRegs.fRegs[%(reg1)d]); |
| ''' % { "reg0" : (2 * reg + 0), |
| "reg1" : (2 * reg + 1) } |
| for sRegs in range(dRegs, 5): |
| loadRegs = '' |
| for reg in range(sRegs): |
| loadRegs += ''' |
| sourceRegs[%(reg)d].fRegs[0] = htog(FpOp1S%(reg)dP0_uw); |
| sourceRegs[%(reg)d].fRegs[1] = htog(FpOp1S%(reg)dP1_uw); |
| ''' % { "reg" : reg } |
| microPackNeonCode = ''' |
| const unsigned perDReg = |
| (2 * sizeof(uint32_t)) / sizeof(Element); |
| |
| union SourceReg { |
| uint32_t fRegs[2]; |
| Element elements[perDReg]; |
| } sourceRegs[%(sRegs)d]; |
| |
| union DestRegs { |
| uint32_t fRegs[2 * %(dRegs)d]; |
| Element elements[%(dRegs)d * perDReg]; |
| } destRegs; |
| |
| %(loadRegs)s |
| |
| for (unsigned i = 0; i < %(sRegs)d; i++) { |
| destRegs.elements[i] = sourceRegs[i].elements[lane]; |
| } |
| for (unsigned i = %(sRegs)d; i < %(dRegs)d * perDReg; ++i) { |
| destRegs.elements[i] = 0; |
| } |
| |
| %(unloadRegs)s |
| ''' % { "sRegs" : sRegs, "dRegs" : dRegs, |
| "loadRegs" : loadRegs, "unloadRegs" : unloadRegs } |
| |
| microPackNeonIop = \ |
| InstObjParams('packneon%dto%duop' % (sRegs * 2, dRegs * 2), |
| 'MicroPackNeon%dto%dUop' % |
| (sRegs * 2, dRegs * 2), |
| 'MicroNeonMixLaneOp', |
| { 'predicate_test': predicateTest, |
| 'code' : microPackNeonCode }, |
| ['IsMicroop']) |
| header_output += MicroNeonMixLaneDeclare.subst(microPackNeonIop) |
| exec_output += MicroNeonMixExecute.subst(microPackNeonIop) |
| }}; |
| |
| let {{ |
| exec_output = '' |
| for typeSize in (8, 16, 32): |
| for sRegs in 1, 2: |
| for dRegs in range(sRegs, min(sRegs * 64 / typeSize + 1, 5)): |
| for format in ("MicroUnpackNeon%(sRegs)dto%(dRegs)dUop", |
| "MicroUnpackAllNeon%(sRegs)dto%(dRegs)dUop", |
| "MicroPackNeon%(dRegs)dto%(sRegs)dUop"): |
| Name = format % { "sRegs" : sRegs * 2, |
| "dRegs" : dRegs * 2 } |
| substDict = { "class_name" : Name, |
| "targs" : "uint%d_t" % typeSize } |
| exec_output += MicroNeonExecDeclare.subst(substDict) |
| }}; |
| |
| //////////////////////////////////////////////////////////////////// |
| // |
| // Integer = Integer op Immediate microops |
| // |
| |
| let {{ |
| microAddiUopIop = InstObjParams('addi_uop', 'MicroAddiUop', |
| 'MicroIntImmOp', |
| {'code': 'URa = URb + imm;', |
| 'predicate_test': predicateTest}, |
| ['IsMicroop']) |
| |
| microAddUopCode = ''' |
| URa = URb + shift_rm_imm(URc, shiftAmt, shiftType, OptShiftRmCondCodesC); |
| ''' |
| |
| microAddXiUopIop = InstObjParams('addxi_uop', 'MicroAddXiUop', |
| 'MicroIntImmXOp', |
| 'XURa = XURb + imm;', |
| ['IsMicroop']) |
| |
| microAddXiSpAlignUopIop = InstObjParams('addxi_uop', 'MicroAddXiSpAlignUop', |
| 'MicroIntImmXOp', ''' |
| if (isSP((IntRegIndex) urb) && bits(XURb, 3, 0) && |
| SPAlignmentCheckEnabled(xc->tcBase())) { |
| return std::make_shared<SPAlignmentFault>(); |
| } |
| XURa = XURb + imm; |
| ''', ['IsMicroop']) |
| |
| microAddXERegUopIop = InstObjParams('addxr_uop', 'MicroAddXERegUop', |
| 'MicroIntRegXOp', |
| 'XURa = XURb + ' + \ |
| 'extendReg64(XURc, type, shiftAmt, 64);', |
| ['IsMicroop']) |
| |
| microAddUopIop = InstObjParams('add_uop', 'MicroAddUop', |
| 'MicroIntRegOp', |
| {'code': microAddUopCode, |
| 'predicate_test': pickPredicate(microAddUopCode)}, |
| ['IsMicroop']) |
| |
| microSubiUopIop = InstObjParams('subi_uop', 'MicroSubiUop', |
| 'MicroIntImmOp', |
| {'code': 'URa = URb - imm;', |
| 'predicate_test': predicateTest}, |
| ['IsMicroop']) |
| |
| microSubXiUopIop = InstObjParams('subxi_uop', 'MicroSubXiUop', |
| 'MicroIntImmXOp', |
| 'XURa = XURb - imm;', |
| ['IsMicroop']) |
| |
| microSubUopCode = ''' |
| URa = URb - shift_rm_imm(URc, shiftAmt, shiftType, OptShiftRmCondCodesC); |
| ''' |
| microSubUopIop = InstObjParams('sub_uop', 'MicroSubUop', |
| 'MicroIntRegOp', |
| {'code': microSubUopCode, |
| 'predicate_test': pickPredicate(microSubUopCode)}, |
| ['IsMicroop']) |
| |
| microUopRegMovIop = InstObjParams('uopReg_uop', 'MicroUopRegMov', |
| 'MicroIntMov', |
| {'code': 'IWRa = URb;', |
| 'predicate_test': predicateTest}, |
| ['IsMicroop']) |
| |
| microUopRegMovRetIop = InstObjParams('movret_uop', 'MicroUopRegMovRet', |
| 'MicroIntMov', |
| {'code': microRetUopCode % 'URb', |
| 'predicate_test': predicateTest}, |
| ['IsMicroop', 'IsNonSpeculative', |
| 'IsSerializeAfter', 'IsSquashAfter']) |
| |
| setPCCPSRDecl = ''' |
| CPSR cpsrOrCondCodes = URc; |
| SCTLR sctlr = Sctlr; |
| pNPC = URa; |
| CPSR new_cpsr = |
| cpsrWriteByInstr(cpsrOrCondCodes, URb, Scr, Nsacr, |
| 0xF, true, sctlr.nmfi, xc->tcBase()); |
| Cpsr = ~CondCodesMask & new_cpsr; |
| NextThumb = new_cpsr.t; |
| NextJazelle = new_cpsr.j; |
| NextItState = ((((CPSR)URb).it2 << 2) & 0xFC) |
| | (((CPSR)URb).it1 & 0x3); |
| CondCodesNZ = new_cpsr.nz; |
| CondCodesC = new_cpsr.c; |
| CondCodesV = new_cpsr.v; |
| CondCodesGE = new_cpsr.ge; |
| ''' |
| |
| microUopSetPCCPSRIop = InstObjParams('uopSet_uop', 'MicroUopSetPCCPSR', |
| 'MicroSetPCCPSR', |
| {'code': setPCCPSRDecl, |
| 'predicate_test': predicateTest}, |
| ['IsMicroop']) |
| |
| header_output = MicroIntImmDeclare.subst(microAddiUopIop) + \ |
| MicroIntImmDeclare.subst(microAddXiUopIop) + \ |
| MicroIntImmDeclare.subst(microAddXiSpAlignUopIop) + \ |
| MicroIntImmDeclare.subst(microSubiUopIop) + \ |
| MicroIntImmDeclare.subst(microSubXiUopIop) + \ |
| MicroIntRegDeclare.subst(microAddUopIop) + \ |
| MicroIntRegDeclare.subst(microSubUopIop) + \ |
| MicroIntXERegDeclare.subst(microAddXERegUopIop) + \ |
| MicroIntMovDeclare.subst(microUopRegMovIop) + \ |
| MicroIntMovDeclare.subst(microUopRegMovRetIop) + \ |
| MicroSetPCCPSRDeclare.subst(microUopSetPCCPSRIop) |
| |
| decoder_output = MicroIntImmConstructor.subst(microAddiUopIop) + \ |
| MicroIntImmXConstructor.subst(microAddXiUopIop) + \ |
| MicroIntImmXConstructor.subst(microAddXiSpAlignUopIop) + \ |
| MicroIntImmConstructor.subst(microSubiUopIop) + \ |
| MicroIntImmXConstructor.subst(microSubXiUopIop) + \ |
| MicroIntRegConstructor.subst(microAddUopIop) + \ |
| MicroIntRegConstructor.subst(microSubUopIop) + \ |
| MicroIntXERegConstructor.subst(microAddXERegUopIop) + \ |
| MicroIntMovConstructor.subst(microUopRegMovIop) + \ |
| MicroIntMovConstructor.subst(microUopRegMovRetIop) + \ |
| MicroSetPCCPSRConstructor.subst(microUopSetPCCPSRIop) |
| |
| exec_output = PredOpExecute.subst(microAddiUopIop) + \ |
| BasicExecute.subst(microAddXiUopIop) + \ |
| BasicExecute.subst(microAddXiSpAlignUopIop) + \ |
| PredOpExecute.subst(microSubiUopIop) + \ |
| BasicExecute.subst(microSubXiUopIop) + \ |
| PredOpExecute.subst(microAddUopIop) + \ |
| PredOpExecute.subst(microSubUopIop) + \ |
| BasicExecute.subst(microAddXERegUopIop) + \ |
| PredOpExecute.subst(microUopRegMovIop) + \ |
| PredOpExecute.subst(microUopRegMovRetIop) + \ |
| PredOpExecute.subst(microUopSetPCCPSRIop) |
| |
| }}; |
| |
| let {{ |
| iop = InstObjParams("ldmstm", "LdmStm", 'MacroMemOp', "", []) |
| header_output = MacroMemDeclare.subst(iop) |
| decoder_output = MacroMemConstructor.subst(iop) |
| |
| iop = InstObjParams("ldpstp", "LdpStp", 'PairMemOp', "", []) |
| header_output += PairMemDeclare.subst(iop) |
| decoder_output += PairMemConstructor.subst(iop) |
| |
| iopImm = InstObjParams("bigfpmemimm", "BigFpMemImm", "BigFpMemImmOp", "") |
| iopPre = InstObjParams("bigfpmempre", "BigFpMemPre", "BigFpMemPreOp", "") |
| iopPost = InstObjParams("bigfpmempost", "BigFpMemPost", "BigFpMemPostOp", "") |
| for iop in (iopImm, iopPre, iopPost): |
| header_output += BigFpMemImmDeclare.subst(iop) |
| decoder_output += BigFpMemImmConstructor.subst(iop) |
| |
| iop = InstObjParams("bigfpmemreg", "BigFpMemReg", "BigFpMemRegOp", "") |
| header_output += BigFpMemRegDeclare.subst(iop) |
| decoder_output += BigFpMemRegConstructor.subst(iop) |
| |
| iop = InstObjParams("bigfpmemlit", "BigFpMemLit", "BigFpMemLitOp", "") |
| header_output += BigFpMemLitDeclare.subst(iop) |
| decoder_output += BigFpMemLitConstructor.subst(iop) |
| |
| iop = InstObjParams("vldmult", "VldMult", 'VldMultOp', "", []) |
| header_output += VMemMultDeclare.subst(iop) |
| decoder_output += VMemMultConstructor.subst(iop) |
| |
| iop = InstObjParams("vldsingle", "VldSingle", 'VldSingleOp', "", []) |
| header_output += VMemSingleDeclare.subst(iop) |
| decoder_output += VMemSingleConstructor.subst(iop) |
| |
| iop = InstObjParams("vstmult", "VstMult", 'VstMultOp', "", []) |
| header_output += VMemMultDeclare.subst(iop) |
| decoder_output += VMemMultConstructor.subst(iop) |
| |
| iop = InstObjParams("vstsingle", "VstSingle", 'VstSingleOp', "", []) |
| header_output += VMemSingleDeclare.subst(iop) |
| decoder_output += VMemSingleConstructor.subst(iop) |
| |
| vfpIop = InstObjParams("vldmstm", "VLdmStm", 'MacroVFPMemOp', "", []) |
| header_output += MacroVFPMemDeclare.subst(vfpIop) |
| decoder_output += MacroVFPMemConstructor.subst(vfpIop) |
| }}; |