| // -*- mode:c++ -*- |
| |
| // Copyright (c) 2012-2013, 2016-2018 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: Thomas Grocutt |
| // Edmund Grimley Evans |
| |
| let {{ |
| |
| header_output = "" |
| decoder_output = "" |
| exec_output = "" |
| |
| fmovImmSCode = vfp64EnabledCheckCode + ''' |
| AA64FpDestP0_uw = bits(imm, 31, 0); |
| AA64FpDestP1_uw = 0; |
| AA64FpDestP2_uw = 0; |
| AA64FpDestP3_uw = 0; |
| ''' |
| fmovImmSIop = InstObjParams("fmov", "FmovImmS", "FpRegImmOp", |
| { "code": fmovImmSCode, |
| "op_class": "FloatMiscOp" }, []) |
| header_output += FpRegImmOpDeclare.subst(fmovImmSIop); |
| decoder_output += FpRegImmOpConstructor.subst(fmovImmSIop); |
| exec_output += BasicExecute.subst(fmovImmSIop); |
| |
| fmovImmDCode = vfp64EnabledCheckCode + ''' |
| AA64FpDestP0_uw = bits(imm, 31, 0); |
| AA64FpDestP1_uw = bits(imm, 63, 32); |
| AA64FpDestP2_uw = 0; |
| AA64FpDestP3_uw = 0; |
| ''' |
| fmovImmDIop = InstObjParams("fmov", "FmovImmD", "FpRegImmOp", |
| { "code": fmovImmDCode, |
| "op_class": "FloatMiscOp" }, []) |
| header_output += FpRegImmOpDeclare.subst(fmovImmDIop); |
| decoder_output += AA64FpRegImmOpConstructor.subst(fmovImmDIop); |
| exec_output += BasicExecute.subst(fmovImmDIop); |
| |
| fmovRegSCode = vfp64EnabledCheckCode + ''' |
| AA64FpDestP0_uw = AA64FpOp1P0_uw; |
| AA64FpDestP1_uw = 0; |
| AA64FpDestP2_uw = 0; |
| AA64FpDestP3_uw = 0; |
| ''' |
| fmovRegSIop = InstObjParams("fmov", "FmovRegS", "FpRegRegOp", |
| { "code": fmovRegSCode, |
| "op_class": "FloatMiscOp" }, []) |
| header_output += FpRegRegOpDeclare.subst(fmovRegSIop); |
| decoder_output += AA64FpRegRegOpConstructor.subst(fmovRegSIop); |
| exec_output += BasicExecute.subst(fmovRegSIop); |
| |
| fmovRegDCode = vfp64EnabledCheckCode + ''' |
| AA64FpDestP0_uw = AA64FpOp1P0_uw; |
| AA64FpDestP1_uw = AA64FpOp1P1_uw; |
| AA64FpDestP2_uw = 0; |
| AA64FpDestP3_uw = 0; |
| ''' |
| fmovRegDIop = InstObjParams("fmov", "FmovRegD", "FpRegRegOp", |
| { "code": fmovRegDCode, |
| "op_class": "FloatMiscOp" }, []) |
| header_output += FpRegRegOpDeclare.subst(fmovRegDIop); |
| decoder_output += AA64FpRegRegOpConstructor.subst(fmovRegDIop); |
| exec_output += BasicExecute.subst(fmovRegDIop); |
| |
| fmovCoreRegWCode = vfp64EnabledCheckCode + ''' |
| AA64FpDestP0_uw = WOp1_uw; |
| AA64FpDestP1_uw = 0; |
| AA64FpDestP2_uw = 0; |
| AA64FpDestP3_uw = 0; |
| ''' |
| fmovCoreRegWIop = InstObjParams("fmov", "FmovCoreRegW", "FpRegRegOp", |
| { "code": fmovCoreRegWCode, |
| "op_class": "FloatMiscOp" }, []) |
| header_output += FpRegRegOpDeclare.subst(fmovCoreRegWIop); |
| decoder_output += AA64FpRegRegOpConstructor.subst(fmovCoreRegWIop); |
| exec_output += BasicExecute.subst(fmovCoreRegWIop); |
| |
| fmovCoreRegXCode = vfp64EnabledCheckCode + ''' |
| AA64FpDestP0_uw = XOp1_ud; |
| AA64FpDestP1_uw = XOp1_ud >> 32; |
| AA64FpDestP2_uw = 0; |
| AA64FpDestP3_uw = 0; |
| ''' |
| fmovCoreRegXIop = InstObjParams("fmov", "FmovCoreRegX", "FpRegRegOp", |
| { "code": fmovCoreRegXCode, |
| "op_class": "FloatMiscOp" }, []) |
| header_output += FpRegRegOpDeclare.subst(fmovCoreRegXIop); |
| decoder_output += AA64FpRegRegOpConstructor.subst(fmovCoreRegXIop); |
| exec_output += BasicExecute.subst(fmovCoreRegXIop); |
| |
| fmovUCoreRegXCode = vfp64EnabledCheckCode + ''' |
| /* Explicitly merge with previous value */ |
| AA64FpDestP0_uw = AA64FpDestP0_uw; |
| AA64FpDestP1_uw = AA64FpDestP1_uw; |
| AA64FpDestP2_uw = XOp1_ud; |
| AA64FpDestP3_uw = XOp1_ud >> 32;''' |
| fmovUCoreRegXIop = InstObjParams("fmov", "FmovUCoreRegX", "FpRegRegOp", |
| { "code": fmovUCoreRegXCode, |
| "op_class": "FloatMiscOp" }, []) |
| header_output += FpRegRegOpDeclare.subst(fmovUCoreRegXIop); |
| decoder_output += AA64FpRegRegOpConstructor.subst(fmovUCoreRegXIop); |
| exec_output += BasicExecute.subst(fmovUCoreRegXIop); |
| |
| fmovRegCoreWCode = vfp64EnabledCheckCode + ''' |
| WDest = AA64FpOp1P0_uw; |
| ''' |
| fmovRegCoreWIop = InstObjParams("fmov", "FmovRegCoreW", "FpRegRegOp", |
| { "code": fmovRegCoreWCode, |
| "op_class": "FloatMiscOp" }, []) |
| header_output += FpRegRegOpDeclare.subst(fmovRegCoreWIop); |
| decoder_output += AA64FpRegRegOpConstructor.subst(fmovRegCoreWIop); |
| exec_output += BasicExecute.subst(fmovRegCoreWIop); |
| |
| fmovRegCoreXCode = vfp64EnabledCheckCode + ''' |
| XDest = ( ((uint64_t) AA64FpOp1P1_uw) << 32) | AA64FpOp1P0_uw; |
| ''' |
| fmovRegCoreXIop = InstObjParams("fmov", "FmovRegCoreX", "FpRegRegOp", |
| { "code": fmovRegCoreXCode, |
| "op_class": "FloatMiscOp" }, []) |
| header_output += FpRegRegOpDeclare.subst(fmovRegCoreXIop); |
| decoder_output += AA64FpRegRegOpConstructor.subst(fmovRegCoreXIop); |
| exec_output += BasicExecute.subst(fmovRegCoreXIop); |
| |
| fmovURegCoreXCode = vfp64EnabledCheckCode + ''' |
| XDest = ( ((uint64_t) AA64FpOp1P3_uw) << 32) | AA64FpOp1P2_uw; |
| ''' |
| fmovURegCoreXIop = InstObjParams("fmov", "FmovURegCoreX", "FpRegRegOp", |
| { "code": fmovURegCoreXCode, |
| "op_class": "FloatMiscOp" }, []) |
| header_output += FpRegRegOpDeclare.subst(fmovURegCoreXIop); |
| decoder_output += AA64FpRegRegOpConstructor.subst(fmovURegCoreXIop); |
| exec_output += BasicExecute.subst(fmovURegCoreXIop); |
| }}; |
| |
| let {{ |
| |
| header_output = "" |
| decoder_output = "" |
| exec_output = "" |
| |
| halfIntConvCode = vfp64EnabledCheckCode + ''' |
| FPSCR fpscr = (FPSCR) FpscrExc; |
| uint16_t cOp1 = AA64FpOp1P0_uw; |
| uint16_t cDest = %(op)s; |
| AA64FpDestP0_uw = cDest; |
| AA64FpDestP1_uw = 0; |
| AA64FpDestP2_uw = 0; |
| AA64FpDestP3_uw = 0; |
| FpscrExc = fpscr; |
| ''' |
| |
| halfIntConvCode2 = vfp64EnabledCheckCode + ''' |
| FPSCR fpscr = (FPSCR) FpscrExc; |
| uint16_t cOp1 = AA64FpOp1P0_uw; |
| uint16_t cOp2 = AA64FpOp2P0_uw; |
| uint16_t cDest = %(op)s; |
| AA64FpDestP0_uw = cDest; |
| AA64FpDestP1_uw = 0; |
| AA64FpDestP2_uw = 0; |
| AA64FpDestP3_uw = 0; |
| FpscrExc = fpscr; |
| ''' |
| |
| halfBinOp = "binaryOp(fpscr, AA64FpOp1P0, AA64FpOp2P0," + \ |
| "%(func)s, fpscr.fz, fpscr.dn, fpscr.rMode)" |
| halfUnaryOp = "unaryOp(fpscr, AA64FpOp1P0," + \ |
| "%(func)s, fpscr.fz, fpscr.rMode)" |
| |
| singleIntConvCode = vfp64EnabledCheckCode + ''' |
| FPSCR fpscr = (FPSCR) FpscrExc; |
| uint32_t cOp1 = AA64FpOp1P0_uw; |
| uint32_t cDest = %(op)s; |
| AA64FpDestP0_uw = cDest; |
| AA64FpDestP1_uw = 0; |
| AA64FpDestP2_uw = 0; |
| AA64FpDestP3_uw = 0; |
| FpscrExc = fpscr; |
| ''' |
| |
| singleIntConvCode2 = vfp64EnabledCheckCode + ''' |
| FPSCR fpscr = (FPSCR) FpscrExc; |
| uint32_t cOp1 = AA64FpOp1P0_uw; |
| uint32_t cOp2 = AA64FpOp2P0_uw; |
| uint32_t cDest = %(op)s; |
| AA64FpDestP0_uw = cDest; |
| AA64FpDestP1_uw = 0; |
| AA64FpDestP2_uw = 0; |
| AA64FpDestP3_uw = 0; |
| FpscrExc = fpscr; |
| ''' |
| |
| singleBinOp = "binaryOp(fpscr, AA64FpOp1P0, AA64FpOp2P0," + \ |
| "%(func)s, fpscr.fz, fpscr.dn, fpscr.rMode)" |
| singleUnaryOp = "unaryOp(fpscr, AA64FpOp1P0, %(func)s, fpscr.fz, fpscr.rMode)" |
| |
| doubleIntConvCode = vfp64EnabledCheckCode + ''' |
| FPSCR fpscr = (FPSCR) FpscrExc; |
| uint64_t cOp1 = ((uint64_t) AA64FpOp1P1_uw) << 32 | AA64FpOp1P0_uw; |
| uint64_t cDest = %(op)s; |
| AA64FpDestP0_uw = cDest & 0xFFFFFFFF; |
| AA64FpDestP1_uw = cDest >> 32; |
| AA64FpDestP2_uw = 0; |
| AA64FpDestP3_uw = 0; |
| FpscrExc = fpscr; |
| ''' |
| |
| doubleIntConvCode2 = vfp64EnabledCheckCode + ''' |
| FPSCR fpscr = (FPSCR) FpscrExc; |
| uint64_t cOp1 = ((uint64_t) AA64FpOp1P1_uw) << 32 | AA64FpOp1P0_uw; |
| uint64_t cOp2 = ((uint64_t) AA64FpOp2P1_uw) << 32 | AA64FpOp2P0_uw; |
| uint64_t cDest = %(op)s; |
| AA64FpDestP0_uw = cDest & 0xFFFFFFFF; |
| AA64FpDestP1_uw = cDest >> 32; |
| AA64FpDestP2_uw = 0; |
| AA64FpDestP3_uw = 0; |
| FpscrExc = fpscr; |
| ''' |
| |
| doubleBinOp = ''' |
| binaryOp(fpscr, dbl(AA64FpOp1P0_uw, AA64FpOp1P1_uw), |
| dbl(AA64FpOp2P0_uw, AA64FpOp2P1_uw), |
| %(func)s, fpscr.fz, fpscr.dn, fpscr.rMode); |
| ''' |
| doubleUnaryOp = ''' |
| unaryOp(fpscr, dbl(AA64FpOp1P0_uw, AA64FpOp1P1_uw), %(func)s, |
| fpscr.fz, fpscr.rMode) |
| ''' |
| |
| def buildTernaryFpOp(name, opClass, hOp, sOp, dOp): |
| global header_output, decoder_output, exec_output |
| for suffix in "D", "S", "H": |
| code = vfp64EnabledCheckCode + ''' |
| FPSCR fpscr = (FPSCR) FpscrExc; |
| ''' |
| if suffix == "H": |
| code += ''' |
| uint16_t cOp1 = AA64FpOp1P0_uw; |
| uint16_t cOp2 = AA64FpOp2P0_uw; |
| uint16_t cOp3 = AA64FpOp3P0_uw; |
| uint16_t cDest; |
| ''' "cDest = " + hOp + ";" + ''' |
| AA64FpDestP0_uw = cDest; |
| AA64FpDestP1_uw = 0; |
| ''' |
| elif suffix == "S": |
| code += ''' |
| uint32_t cOp1 = AA64FpOp1P0_uw; |
| uint32_t cOp2 = AA64FpOp2P0_uw; |
| uint32_t cOp3 = AA64FpOp3P0_uw; |
| uint32_t cDest; |
| ''' "cDest = " + sOp + ";" + ''' |
| AA64FpDestP0_uw = cDest; |
| AA64FpDestP1_uw = 0; |
| ''' |
| elif suffix == "D": |
| code += ''' |
| uint64_t cOp1 = AA64FpOp1P0_uw | (uint64_t)AA64FpOp1P1_uw << 32; |
| uint64_t cOp2 = AA64FpOp2P0_uw | (uint64_t)AA64FpOp2P1_uw << 32; |
| uint64_t cOp3 = AA64FpOp3P0_uw | (uint64_t)AA64FpOp3P1_uw << 32; |
| uint64_t cDest; |
| ''' "cDest = " + dOp + ";" + ''' |
| AA64FpDestP0_uw = cDest; |
| AA64FpDestP1_uw = cDest >> 32; |
| ''' |
| code += ''' |
| AA64FpDestP2_uw = 0; |
| AA64FpDestP3_uw = 0; |
| FpscrExc = fpscr; |
| ''' |
| |
| iop = InstObjParams(name.lower(), name + suffix, |
| "FpRegRegRegRegOp", |
| { "code": code, "op_class": opClass }, []) |
| |
| header_output += AA64FpRegRegRegRegOpDeclare.subst(iop) |
| decoder_output += AA64FpRegRegRegRegOpConstructor.subst(iop) |
| exec_output += BasicExecute.subst(iop) |
| |
| buildTernaryFpOp("FMAdd", "FloatMultAccOp", |
| "fplibMulAdd<uint16_t>(cOp3, cOp1, cOp2, fpscr)", |
| "fplibMulAdd<uint32_t>(cOp3, cOp1, cOp2, fpscr)", |
| "fplibMulAdd<uint64_t>(cOp3, cOp1, cOp2, fpscr)" ) |
| buildTernaryFpOp("FMSub", "FloatMultAccOp", |
| "fplibMulAdd<uint16_t>(cOp3, fplibNeg<uint32_t>(cOp1), cOp2, fpscr)", |
| "fplibMulAdd<uint32_t>(cOp3, fplibNeg<uint32_t>(cOp1), cOp2, fpscr)", |
| "fplibMulAdd<uint64_t>(cOp3, fplibNeg<uint64_t>(cOp1), cOp2, fpscr)" ) |
| buildTernaryFpOp("FNMAdd", "FloatMultAccOp", |
| "fplibMulAdd<uint16_t>(fplibNeg<uint16_t>(cOp3), " + |
| "fplibNeg<uint16_t>(cOp1), cOp2, fpscr)", |
| "fplibMulAdd<uint32_t>(fplibNeg<uint32_t>(cOp3), " + |
| "fplibNeg<uint32_t>(cOp1), cOp2, fpscr)", |
| "fplibMulAdd<uint64_t>(fplibNeg<uint64_t>(cOp3), " + |
| "fplibNeg<uint64_t>(cOp1), cOp2, fpscr)" ) |
| buildTernaryFpOp("FNMSub", "FloatMultAccOp", |
| "fplibMulAdd<uint16_t>(fplibNeg<uint32_t>(cOp3), cOp1, cOp2, fpscr)", |
| "fplibMulAdd<uint32_t>(fplibNeg<uint32_t>(cOp3), cOp1, cOp2, fpscr)", |
| "fplibMulAdd<uint64_t>(fplibNeg<uint64_t>(cOp3), cOp1, cOp2, fpscr)" ) |
| |
| def buildBinFpOp(name, Name, base, opClass, halfOp, singleOp, doubleOp): |
| global header_output, decoder_output, exec_output |
| |
| code = halfIntConvCode2 % { "op": halfOp } |
| hIop = InstObjParams(name, Name + "H", base, |
| { "code": code, |
| "op_class": opClass }, []) |
| |
| code = singleIntConvCode2 % { "op": singleOp } |
| sIop = InstObjParams(name, Name + "S", base, |
| { "code": code, |
| "op_class": opClass }, []) |
| |
| code = doubleIntConvCode2 % { "op": doubleOp } |
| dIop = InstObjParams(name, Name + "D", base, |
| { "code": code, |
| "op_class": opClass }, []) |
| |
| declareTempl = eval( base + "Declare"); |
| constructorTempl = eval("AA64" + base + "Constructor"); |
| |
| for iop in hIop, sIop, dIop: |
| header_output += declareTempl.subst(iop) |
| decoder_output += constructorTempl.subst(iop) |
| exec_output += BasicExecute.subst(iop) |
| |
| buildBinFpOp("fadd", "FAdd", "FpRegRegRegOp", "FloatAddOp", |
| "fplibAdd<uint16_t>(cOp1, cOp2, fpscr)", |
| "fplibAdd<uint32_t>(cOp1, cOp2, fpscr)", |
| "fplibAdd<uint64_t>(cOp1, cOp2, fpscr)") |
| buildBinFpOp("fsub", "FSub", "FpRegRegRegOp", "FloatAddOp", |
| "fplibSub<uint16_t>(cOp1, cOp2, fpscr)", |
| "fplibSub<uint32_t>(cOp1, cOp2, fpscr)", |
| "fplibSub<uint64_t>(cOp1, cOp2, fpscr)") |
| buildBinFpOp("fdiv", "FDiv", "FpRegRegRegOp", "FloatDivOp", |
| "fplibDiv<uint16_t>(cOp1, cOp2, fpscr)", |
| "fplibDiv<uint32_t>(cOp1, cOp2, fpscr)", |
| "fplibDiv<uint64_t>(cOp1, cOp2, fpscr)") |
| buildBinFpOp("fmul", "FMul", "FpRegRegRegOp", "FloatMultOp", |
| "fplibMul<uint16_t>(cOp1, cOp2, fpscr)", |
| "fplibMul<uint32_t>(cOp1, cOp2, fpscr)", |
| "fplibMul<uint64_t>(cOp1, cOp2, fpscr)") |
| buildBinFpOp("fnmul", "FNMul", "FpRegRegRegOp", "FloatMultOp", |
| "fplibNeg<uint16_t>(fplibMul<uint32_t>(cOp1, cOp2, fpscr))", |
| "fplibNeg<uint32_t>(fplibMul<uint32_t>(cOp1, cOp2, fpscr))", |
| "fplibNeg<uint64_t>(fplibMul<uint64_t>(cOp1, cOp2, fpscr))") |
| buildBinFpOp("fmin", "FMin", "FpRegRegRegOp", "FloatCmpOp", |
| "fplibMin<uint16_t>(cOp1, cOp2, fpscr)", |
| "fplibMin<uint32_t>(cOp1, cOp2, fpscr)", |
| "fplibMin<uint64_t>(cOp1, cOp2, fpscr)") |
| buildBinFpOp("fmax", "FMax", "FpRegRegRegOp", "FloatCmpOp", |
| "fplibMax<uint16_t>(cOp1, cOp2, fpscr)", |
| "fplibMax<uint32_t>(cOp1, cOp2, fpscr)", |
| "fplibMax<uint64_t>(cOp1, cOp2, fpscr)") |
| buildBinFpOp("fminnm", "FMinNM", "FpRegRegRegOp", "FloatCmpOp", |
| "fplibMinNum<uint16_t>(cOp1, cOp2, fpscr)", |
| "fplibMinNum<uint32_t>(cOp1, cOp2, fpscr)", |
| "fplibMinNum<uint64_t>(cOp1, cOp2, fpscr)") |
| buildBinFpOp("fmaxnm", "FMaxNM", "FpRegRegRegOp", "FloatCmpOp", |
| "fplibMaxNum<uint16_t>(cOp1, cOp2, fpscr)", |
| "fplibMaxNum<uint32_t>(cOp1, cOp2, fpscr)", |
| "fplibMaxNum<uint64_t>(cOp1, cOp2, fpscr)") |
| |
| def buildUnaryFpOp(name, Name, base, opClass, |
| halfOp, singleOp, doubleOp = None): |
| if doubleOp is None: |
| doubleOp = singleOp |
| global header_output, decoder_output, exec_output |
| |
| code = halfIntConvCode % { "op": halfOp } |
| hIop = InstObjParams(name, Name + "H", base, |
| { "code": code, |
| "op_class": opClass }, []) |
| code = singleIntConvCode % { "op": singleOp } |
| sIop = InstObjParams(name, Name + "S", base, |
| { "code": code, |
| "op_class": opClass }, []) |
| code = doubleIntConvCode % { "op": doubleOp } |
| dIop = InstObjParams(name, Name + "D", base, |
| { "code": code, |
| "op_class": opClass }, []) |
| |
| declareTempl = eval( base + "Declare"); |
| constructorTempl = eval("AA64" + base + "Constructor"); |
| |
| for iop in hIop, sIop, dIop: |
| header_output += declareTempl.subst(iop) |
| decoder_output += constructorTempl.subst(iop) |
| exec_output += BasicExecute.subst(iop) |
| |
| buildUnaryFpOp("fsqrt", "FSqrt", "FpRegRegOp", "FloatSqrtOp", |
| "fplibSqrt<uint16_t>(cOp1, fpscr)", |
| "fplibSqrt<uint32_t>(cOp1, fpscr)", |
| "fplibSqrt<uint64_t>(cOp1, fpscr)") |
| |
| def buildSimpleUnaryFpOp(name, Name, base, opClass, halfOp, singleOp, |
| doubleOp = None, isIntConv = True): |
| if doubleOp is None: |
| doubleOp = singleOp |
| global header_output, decoder_output, exec_output |
| |
| if isIntConv: |
| hCode = halfIntConvCode |
| sCode = singleIntConvCode |
| dCode = doubleIntConvCode |
| else: |
| hCode = halfCode |
| sCode = singleCode |
| dCode = doubleCode |
| |
| for code, op, suffix in [[hCode, halfOp, "H"], |
| [sCode, singleOp, "S"], |
| [dCode, doubleOp, "D"]]: |
| iop = InstObjParams(name, Name + suffix, base, |
| { "code": code % { "op": op }, |
| "op_class": opClass }, []) |
| |
| declareTempl = eval( base + "Declare"); |
| constructorTempl = eval("AA64" + base + "Constructor"); |
| |
| header_output += declareTempl.subst(iop) |
| decoder_output += constructorTempl.subst(iop) |
| exec_output += BasicExecute.subst(iop) |
| |
| buildSimpleUnaryFpOp("fneg", "FNeg", "FpRegRegOp", "FloatMiscOp", |
| "fplibNeg<uint16_t>(cOp1)", |
| "fplibNeg<uint32_t>(cOp1)", |
| "fplibNeg<uint64_t>(cOp1)") |
| buildSimpleUnaryFpOp("fabs", "FAbs", "FpRegRegOp", "FloatMiscOp", |
| "fplibAbs<uint16_t>(cOp1)", |
| "fplibAbs<uint32_t>(cOp1)", |
| "fplibAbs<uint64_t>(cOp1)") |
| buildSimpleUnaryFpOp("frintn", "FRIntN", "FpRegRegOp", "FloatMiscOp", |
| "fplibRoundInt<uint16_t>(cOp1, FPRounding_TIEEVEN, false, fpscr)", |
| "fplibRoundInt<uint32_t>(cOp1, FPRounding_TIEEVEN, false, fpscr)", |
| "fplibRoundInt<uint64_t>(cOp1, FPRounding_TIEEVEN, false, fpscr)") |
| buildSimpleUnaryFpOp("frintp", "FRIntP", "FpRegRegOp", "FloatMiscOp", |
| "fplibRoundInt<uint16_t>(cOp1, FPRounding_POSINF, false, fpscr)", |
| "fplibRoundInt<uint32_t>(cOp1, FPRounding_POSINF, false, fpscr)", |
| "fplibRoundInt<uint64_t>(cOp1, FPRounding_POSINF, false, fpscr)") |
| buildSimpleUnaryFpOp("frintm", "FRIntM", "FpRegRegOp", "FloatMiscOp", |
| "fplibRoundInt<uint16_t>(cOp1, FPRounding_NEGINF, false, fpscr)", |
| "fplibRoundInt<uint32_t>(cOp1, FPRounding_NEGINF, false, fpscr)", |
| "fplibRoundInt<uint64_t>(cOp1, FPRounding_NEGINF, false, fpscr)") |
| buildSimpleUnaryFpOp("frintz", "FRIntZ", "FpRegRegOp", "FloatMiscOp", |
| "fplibRoundInt<uint16_t>(cOp1, FPRounding_ZERO, false, fpscr)", |
| "fplibRoundInt<uint32_t>(cOp1, FPRounding_ZERO, false, fpscr)", |
| "fplibRoundInt<uint64_t>(cOp1, FPRounding_ZERO, false, fpscr)") |
| buildSimpleUnaryFpOp("frinta", "FRIntA", "FpRegRegOp", "FloatMiscOp", |
| "fplibRoundInt<uint16_t>(cOp1, FPRounding_TIEAWAY, false, fpscr)", |
| "fplibRoundInt<uint32_t>(cOp1, FPRounding_TIEAWAY, false, fpscr)", |
| "fplibRoundInt<uint64_t>(cOp1, FPRounding_TIEAWAY, false, fpscr)") |
| buildSimpleUnaryFpOp("frinti", "FRIntI", "FpRegRegOp", "FloatMiscOp", |
| "fplibRoundInt<uint16_t>(cOp1, FPCRRounding(fpscr), false, fpscr)", |
| "fplibRoundInt<uint32_t>(cOp1, FPCRRounding(fpscr), false, fpscr)", |
| "fplibRoundInt<uint64_t>(cOp1, FPCRRounding(fpscr), false, fpscr)") |
| buildSimpleUnaryFpOp("frintx", "FRIntX", "FpRegRegOp", "FloatMiscOp", |
| "fplibRoundInt<uint16_t>(cOp1, FPCRRounding(fpscr), true, fpscr)", |
| "fplibRoundInt<uint32_t>(cOp1, FPCRRounding(fpscr), true, fpscr)", |
| "fplibRoundInt<uint64_t>(cOp1, FPCRRounding(fpscr), true, fpscr)") |
| }}; |
| |
| let {{ |
| |
| header_output = "" |
| decoder_output = "" |
| exec_output = "" |
| |
| # Creates the integer to floating point instructions, including variants for |
| # signed/unsigned, float/double, etc |
| for regL, regOpL, width in [["W", "w", 32], |
| ["X", "d", 64]]: |
| for isDouble in True, False: |
| for us, usCode in [["U", "uint%d_t cSrc = %sOp1_u%s;" %(width, regL, regOpL)], |
| ["S", "int%d_t cSrc = %sOp1_u%s;" %(width, regL, regOpL)]]: |
| fcvtIntFpDCode = vfp64EnabledCheckCode + ''' |
| FPSCR fpscr = (FPSCR) FpscrExc; |
| %s |
| ''' %(usCode) |
| |
| if isDouble: |
| fcvtIntFpDCode += ''' |
| uint64_t cDest = fplibFixedToFP<uint64_t>(cSrc, 0, |
| %s, FPCRRounding(fpscr), fpscr); |
| AA64FpDestP0_uw = cDest; |
| AA64FpDestP1_uw = cDest >> 32; |
| ''' % ("true" if us == "U" else "false") |
| else: |
| fcvtIntFpDCode += ''' |
| uint32_t cDest = fplibFixedToFP<uint32_t>(cSrc, 0, |
| %s, FPCRRounding(fpscr), fpscr); |
| AA64FpDestP0_uw = cDest; |
| AA64FpDestP1_uw = 0; |
| ''' % ("true" if us == "U" else "false") |
| fcvtIntFpDCode += ''' |
| AA64FpDestP2_uw = 0; |
| AA64FpDestP3_uw = 0; |
| FpscrExc = fpscr; |
| ''' |
| |
| instName = "Fcvt%s%sIntFp%s" %(regL, us, "D" if isDouble else "S") |
| mnem = "%scvtf" %(us.lower()) |
| fcvtIntFpDIop = InstObjParams(mnem, instName, "FpRegRegOp", |
| { "code": fcvtIntFpDCode, |
| "op_class": "FloatCvtOp" }, []) |
| header_output += FpRegRegOpDeclare.subst(fcvtIntFpDIop); |
| decoder_output += AA64FpRegRegOpConstructor.subst(fcvtIntFpDIop); |
| exec_output += BasicExecute.subst(fcvtIntFpDIop); |
| |
| # Generates the floating point to integer conversion instructions in various |
| # variants, eg signed/unsigned |
| def buildFpCvtIntOp(isDouble, isSigned, isXReg): |
| global header_output, decoder_output, exec_output |
| |
| for rmode, roundingMode in [["N", "FPRounding_TIEEVEN"], |
| ["P", "FPRounding_POSINF"], |
| ["M", "FPRounding_NEGINF"], |
| ["Z", "FPRounding_ZERO"], |
| ["A", "FPRounding_TIEAWAY"]]: |
| fcvtFpIntCode = vfp64EnabledCheckCode + ''' |
| FPSCR fpscr = (FPSCR) FpscrExc;''' |
| if isDouble: |
| fcvtFpIntCode += ''' |
| uint64_t cOp1 = AA64FpOp1P0_uw | (uint64_t)AA64FpOp1P1_uw << 32; |
| ''' |
| else: |
| fcvtFpIntCode += "uint32_t cOp1 = AA64FpOp1P0_uw;" |
| |
| fcvtFpIntCode += ''' |
| %sDest = fplibFPToFixed<uint%s_t, uint%s_t>(cOp1, 0, %s, %s, fpscr); |
| FpscrExc = fpscr; |
| ''' %("X" if isXReg else "W", |
| "64" if isDouble else "32", |
| "64" if isXReg else "32", |
| "false" if isSigned else "true", |
| roundingMode) |
| |
| instName = "FcvtFp%sInt%s%s%s" %("S" if isSigned else "U", |
| "X" if isXReg else "W", |
| "D" if isDouble else "S", rmode) |
| mnem = "fcvt%s%s" %(rmode, "s" if isSigned else "u") |
| fcvtFpIntIop = InstObjParams(mnem, instName, "FpRegRegOp", |
| { "code": fcvtFpIntCode, |
| "op_class": "FloatCvtOp" }, []) |
| header_output += FpRegRegOpDeclare.subst(fcvtFpIntIop); |
| decoder_output += FpRegRegOpConstructor.subst(fcvtFpIntIop); |
| exec_output += BasicExecute.subst(fcvtFpIntIop); |
| |
| # Now actually do the building with the different variants |
| for isDouble in True, False: |
| for isSigned in True, False: |
| for isXReg in True, False: |
| buildFpCvtIntOp(isDouble, isSigned, isXReg) |
| |
| fcvtFpSFpDCode = vfp64EnabledCheckCode + ''' |
| FPSCR fpscr = (FPSCR) FpscrExc; |
| uint64_t cDest = fplibConvert<uint32_t, uint64_t>(AA64FpOp1P0_uw, |
| FPCRRounding(fpscr), fpscr); |
| AA64FpDestP0_uw = cDest; |
| AA64FpDestP1_uw = cDest >> 32; |
| AA64FpDestP2_uw = 0; |
| AA64FpDestP3_uw = 0; |
| FpscrExc = fpscr; |
| ''' |
| fcvtFpSFpDIop = InstObjParams("fcvt", "FCvtFpSFpD", "FpRegRegOp", |
| { "code": fcvtFpSFpDCode, |
| "op_class": "FloatCvtOp" }, []) |
| header_output += FpRegRegOpDeclare.subst(fcvtFpSFpDIop); |
| decoder_output += AA64FpRegRegOpConstructor.subst(fcvtFpSFpDIop); |
| exec_output += BasicExecute.subst(fcvtFpSFpDIop); |
| |
| fcvtFpDFpSCode = vfp64EnabledCheckCode + ''' |
| FPSCR fpscr = (FPSCR) FpscrExc; |
| uint64_t cOp1 = AA64FpOp1P0_uw | (uint64_t)AA64FpOp1P1_uw << 32; |
| AA64FpDestP0_uw = fplibConvert<uint64_t, uint32_t>(cOp1, |
| FPCRRounding(fpscr), fpscr); |
| AA64FpDestP1_uw = 0; |
| AA64FpDestP2_uw = 0; |
| AA64FpDestP3_uw = 0; |
| FpscrExc = fpscr; |
| ''' |
| fcvtFpDFpSIop = InstObjParams("fcvt", "FcvtFpDFpS", "FpRegRegOp", |
| {"code": fcvtFpDFpSCode, |
| "op_class": "FloatCvtOp" }, []) |
| header_output += FpRegRegOpDeclare.subst(fcvtFpDFpSIop); |
| decoder_output += AA64FpRegRegOpConstructor.subst(fcvtFpDFpSIop); |
| exec_output += BasicExecute.subst(fcvtFpDFpSIop); |
| |
| # Half precision to single or double precision conversion |
| for isDouble in True, False: |
| code = vfp64EnabledCheckCode + ''' |
| FPSCR fpscr = (FPSCR) FpscrExc; |
| %s cDest = fplibConvert<uint16_t, uint%s_t>(AA64FpOp1P0_uw, |
| FPCRRounding(fpscr), fpscr); |
| ''' % ("uint64_t" if isDouble else "uint32_t", |
| "64" if isDouble else "32") |
| if isDouble: |
| code += ''' |
| AA64FpDestP0_uw = cDest; |
| AA64FpDestP1_uw = cDest >> 32; |
| ''' |
| else: |
| code += ''' |
| AA64FpDestP0_uw = cDest; |
| AA64FpDestP1_uw = 0; |
| ''' |
| code += ''' |
| AA64FpDestP2_uw = 0; |
| AA64FpDestP3_uw = 0; |
| FpscrExc = fpscr; |
| ''' |
| |
| instName = "FcvtFpHFp%s" %("D" if isDouble else "S") |
| fcvtFpHFpIop = InstObjParams("fcvt", instName, "FpRegRegOp", |
| { "code": code, |
| "op_class": "FloatCvtOp" }, []) |
| header_output += FpRegRegOpDeclare.subst(fcvtFpHFpIop); |
| decoder_output += AA64FpRegRegOpConstructor.subst(fcvtFpHFpIop); |
| exec_output += BasicExecute.subst(fcvtFpHFpIop); |
| |
| # single or double precision to Half precision conversion |
| for isDouble in True, False: |
| code = vfp64EnabledCheckCode + ''' |
| FPSCR fpscr = (FPSCR) FpscrExc; |
| %s; |
| AA64FpDestP0_uw = fplibConvert<uint%s_t, uint16_t>(cOp1, |
| FPCRRounding(fpscr), fpscr); |
| AA64FpDestP1_uw = 0; |
| AA64FpDestP2_uw = 0; |
| AA64FpDestP3_uw = 0; |
| FpscrExc = fpscr; |
| ''' % ("uint64_t cOp1 = AA64FpOp1P0_uw | (uint64_t)AA64FpOp1P1_uw << 32" |
| if isDouble else "uint32_t cOp1 = AA64FpOp1P0_uw", |
| "64" if isDouble else "32") |
| |
| instName = "FcvtFp%sFpH" %("D" if isDouble else "S") |
| fcvtFpFpHIop = InstObjParams("fcvt", instName, "FpRegRegOp", |
| { "code": code, |
| "op_class": "FloatCvtOp" }, []) |
| header_output += FpRegRegOpDeclare.subst(fcvtFpFpHIop); |
| decoder_output += AA64FpRegRegOpConstructor.subst(fcvtFpFpHIop); |
| exec_output += BasicExecute.subst(fcvtFpFpHIop); |
| |
| # Build the various versions of the floating point compare instructions |
| def buildFCmpOp(isQuiet, isDouble, isImm): |
| global header_output, decoder_output, exec_output |
| |
| fcmpCode = vfp64EnabledCheckCode + ''' |
| FPSCR fpscr = (FPSCR) FpscrExc; |
| %s cOp1 = %s; |
| ''' % ("uint64_t" if isDouble else "uint32_t", |
| "AA64FpDestP0_uw | (uint64_t)AA64FpDestP1_uw << 32" |
| if isDouble else "AA64FpDestP0_uw") |
| if isImm: |
| fcmpCode += ''' |
| %s cOp2 = imm; |
| ''' % ("uint64_t" if isDouble else "uint32_t") |
| else: |
| fcmpCode += ''' |
| %s cOp2 = %s; |
| ''' % ("uint64_t" if isDouble else "uint32_t", |
| "AA64FpOp1P0_uw | (uint64_t)AA64FpOp1P1_uw << 32" |
| if isDouble else "AA64FpOp1P0_uw") |
| fcmpCode += ''' |
| int cc = fplibCompare<uint%s_t>(cOp1, cOp2, %s, fpscr); |
| CondCodesNZ = cc >> 2 & 3; |
| CondCodesC = cc >> 1 & 1; |
| CondCodesV = cc & 1; |
| FpCondCodes = fpscr & FpCondCodesMask; |
| FpscrExc = fpscr; |
| ''' % ("64" if isDouble else "32", "false" if isQuiet else "true") |
| |
| typeName = "Imm" if isImm else "Reg" |
| instName = "FCmp%s%s%s" %("" if isQuiet else "E", typeName, |
| "D" if isDouble else "S") |
| fcmpIop = InstObjParams("fcmp%s" %("" if isQuiet else "e"), instName, |
| "FpReg%sOp" %(typeName), |
| {"code": fcmpCode, |
| "op_class": "FloatCmpOp"}, []) |
| |
| declareTemp = eval("FpReg%sOpDeclare" %(typeName)); |
| constructorTemp = eval("AA64FpReg%sOpConstructor" %(typeName)); |
| header_output += declareTemp.subst(fcmpIop); |
| decoder_output += constructorTemp.subst(fcmpIop); |
| exec_output += BasicExecute.subst(fcmpIop); |
| |
| for isQuiet in True, False: |
| for isDouble in True, False: |
| for isImm in True, False: |
| buildFCmpOp(isQuiet, isDouble, isImm) |
| |
| # Build the various versions of the conditional floating point compare |
| # instructions |
| def buildFCCmpOp(isQuiet, isDouble): |
| global header_output, decoder_output, exec_output |
| |
| fccmpCode = vfp64EnabledCheckCode + ''' |
| FPSCR fpscr = (FPSCR) FpscrExc; |
| if (testPredicate(CondCodesNZ, CondCodesC, CondCodesV, condCode)) { |
| %s cOp1 = %s; |
| %s cOp2 = %s; |
| int cc = fplibCompare<uint%s_t>(cOp1, cOp2, %s, fpscr); |
| CondCodesNZ = cc >> 2 & 3; |
| CondCodesC = cc >> 1 & 1; |
| CondCodesV = cc & 1; |
| } else { |
| CondCodesNZ = (defCc >> 2) & 0x3; |
| CondCodesC = (defCc >> 1) & 0x1; |
| CondCodesV = defCc & 0x1; |
| } |
| FpCondCodes = fpscr & FpCondCodesMask; |
| FpscrExc = fpscr; |
| ''' % ("uint64_t" if isDouble else "uint32_t", |
| "AA64FpOp1P0_uw | (uint64_t)AA64FpOp1P1_uw << 32" |
| if isDouble else "AA64FpOp1P0_uw", |
| "uint64_t" if isDouble else "uint32_t", |
| "AA64FpOp2P0_uw | (uint64_t)AA64FpOp2P1_uw << 32" |
| if isDouble else "AA64FpOp2P0_uw", |
| "64" if isDouble else "32", "false" if isQuiet else "true") |
| |
| instName = "FCCmp%sReg%s" %("" if isQuiet else "E", |
| "D" if isDouble else "S") |
| fccmpIop = InstObjParams("fccmp%s" %("" if isQuiet else "e"), |
| instName, "FpCondCompRegOp", |
| {"code": fccmpCode, |
| "op_class": "FloatCmpOp"}, []) |
| header_output += DataXCondCompRegDeclare.subst(fccmpIop); |
| decoder_output += DataXCondCompRegConstructor.subst(fccmpIop); |
| exec_output += BasicExecute.subst(fccmpIop); |
| |
| for isQuiet in True, False: |
| for isDouble in True, False: |
| buildFCCmpOp(isQuiet, isDouble) |
| |
| }}; |
| |
| let {{ |
| |
| header_output = "" |
| decoder_output = "" |
| exec_output = "" |
| |
| # Generates the variants of the floating to fixed point instructions |
| def buildFpCvtFixedOp(isSigned, isDouble, isXReg): |
| global header_output, decoder_output, exec_output |
| |
| fcvtFpFixedCode = vfp64EnabledCheckCode + ''' |
| FPSCR fpscr = (FPSCR) FpscrExc; |
| ''' |
| if isDouble: |
| fcvtFpFixedCode += ''' |
| uint64_t cOp1 = AA64FpOp1P0_uw | (uint64_t)AA64FpOp1P1_uw << 32; |
| ''' |
| else: |
| fcvtFpFixedCode += "uint32_t cOp1 = AA64FpOp1P0_uw;" |
| fcvtFpFixedCode += ''' |
| %sDest = fplibFPToFixed<uint%s_t, uint%s_t>(cOp1, 64 - imm, %s, |
| FPRounding_ZERO, fpscr); |
| FpscrExc = fpscr; |
| ''' %("X" if isXReg else "W", |
| "64" if isDouble else "32", |
| "64" if isXReg else "32", |
| "false" if isSigned else "true") |
| |
| instName = "FcvtFp%sFixed%s%s" %("S" if isSigned else "U", |
| "D" if isDouble else "S", |
| "X" if isXReg else "W") |
| mnem = "fcvtz%s" %("s" if isSigned else "u") |
| fcvtFpFixedIop = InstObjParams(mnem, instName, "FpRegRegImmOp", |
| { "code": fcvtFpFixedCode, |
| "op_class": "FloatCvtOp" }, []) |
| header_output += FpRegRegImmOpDeclare.subst(fcvtFpFixedIop); |
| decoder_output += AA64FpRegRegImmOpConstructor.subst(fcvtFpFixedIop); |
| exec_output += BasicExecute.subst(fcvtFpFixedIop); |
| |
| # Generates the variants of the fixed to floating point instructions |
| def buildFixedCvtFpOp(isSigned, isDouble, isXReg): |
| global header_output, decoder_output, exec_output |
| |
| srcRegType = "X" if isXReg else "W" |
| fcvtFixedFpCode = vfp64EnabledCheckCode + ''' |
| FPSCR fpscr = (FPSCR) FpscrExc; |
| %s result = fplibFixedToFP<uint%s_t>((%s%s_t)%sOp1, 64 - imm, |
| %s, FPCRRounding(fpscr), fpscr); |
| ''' %("uint64_t" if isDouble else "uint32_t", |
| "64" if isDouble else "32", |
| "int" if isSigned else "uint", "64" if isXReg else "32", |
| srcRegType, |
| "false" if isSigned else "true") |
| if isDouble: |
| fcvtFixedFpCode += ''' |
| AA64FpDestP0_uw = result; |
| AA64FpDestP1_uw = result >> 32; |
| ''' |
| else: |
| fcvtFixedFpCode += ''' |
| AA64FpDestP0_uw = result; |
| AA64FpDestP1_uw = 0; |
| ''' |
| fcvtFixedFpCode += ''' |
| AA64FpDestP2_uw = 0; |
| AA64FpDestP3_uw = 0; |
| FpscrExc = fpscr; |
| ''' |
| |
| instName = "Fcvt%sFixedFp%s%s" %("S" if isSigned else "U", |
| "D" if isDouble else "S", |
| srcRegType) |
| mnem = "%scvtf" %("s" if isSigned else "u") |
| fcvtFixedFpIop = InstObjParams(mnem, instName, "FpRegRegImmOp", |
| { "code": fcvtFixedFpCode, |
| "op_class": "FloatCvtOp" }, []) |
| header_output += FpRegRegImmOpDeclare.subst(fcvtFixedFpIop); |
| decoder_output += FpRegRegImmOpConstructor.subst(fcvtFixedFpIop); |
| exec_output += BasicExecute.subst(fcvtFixedFpIop); |
| |
| # loop over the variants building the instructions for each |
| for isXReg in True, False: |
| for isDouble in True, False: |
| for isSigned in True, False: |
| buildFpCvtFixedOp(isSigned, isDouble, isXReg) |
| buildFixedCvtFpOp(isSigned, isDouble, isXReg) |
| }}; |
| |
| let {{ |
| |
| header_output = "" |
| decoder_output = "" |
| exec_output = "" |
| |
| for isDouble in True, False: |
| code = ''' |
| if (testPredicate(CondCodesNZ, CondCodesC, CondCodesV, condCode)) { |
| AA64FpDestP0_uw = AA64FpOp1P0_uw; |
| ''' |
| if isDouble: |
| code += ''' |
| AA64FpDestP1_uw = AA64FpOp1P1_uw; |
| } else { |
| AA64FpDestP0_uw = AA64FpOp2P0_uw; |
| AA64FpDestP1_uw = AA64FpOp2P1_uw; |
| } |
| ''' |
| else: |
| code += ''' |
| } else { |
| AA64FpDestP0_uw = AA64FpOp2P0_uw; |
| } |
| AA64FpDestP1_uw = 0; |
| ''' |
| code += ''' |
| AA64FpDestP2_uw = 0; |
| AA64FpDestP3_uw = 0; |
| ''' |
| |
| iop = InstObjParams("fcsel", "FCSel%s" %("D" if isDouble else "S"), |
| "FpCondSelOp", { "code": code, |
| "op_class": "FloatCvtOp" }) |
| header_output += DataXCondSelDeclare.subst(iop) |
| decoder_output += DataXCondSelConstructor.subst(iop) |
| exec_output += BasicExecute.subst(iop) |
| }}; |