arch-arm: Implement ARMv8.3-JSConv

This commit implements Armv8 javascript float point convertion instructions
VJVCT and FJCVTZS.

Change-Id: I1b24839daef775bbb1eb9da5f32c4bb3843e0b28
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/25023
Reviewed-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
Maintainer: Giacomo Travaglini <giacomo.travaglini@arm.com>
Tested-by: kokoro <noreply+kokoro@google.com>
diff --git a/src/arch/arm/insts/fplib.cc b/src/arch/arm/insts/fplib.cc
index 49305ec..460ca7c 100644
--- a/src/arch/arm/insts/fplib.cc
+++ b/src/arch/arm/insts/fplib.cc
@@ -1,5 +1,6 @@
 /*
 * Copyright (c) 2012-2013, 2017-2018 ARM Limited
+* Copyright (c) 2020 Metempsy Technology Consulting
 * All rights reserved
 *
 * The license below extends only to copyright in the software and shall
@@ -37,10 +38,10 @@
 * Authors: Edmund Grimley Evans
 *          Thomas Grocutt
 */
-
 #include <stdint.h>
 
 #include <cassert>
+#include <cmath>
 
 #include "base/logging.hh"
 #include "fplib.hh"
@@ -429,6 +430,8 @@
 fp64_unpack(int *sgn, int *exp, uint64_t *mnt, uint64_t x, int mode,
             int *flags)
 {
+
+
     *sgn = x >> (FP64_BITS - 1);
     *exp = FP64_EXP(x);
     *mnt = FP64_MANT(x);
@@ -4737,6 +4740,71 @@
     return result;
 }
 
+uint32_t
+fplibFPToFixedJS(uint64_t op, FPSCR &fpscr, bool is64, uint8_t& nz)
+{
+    int flags = 0;
+    uint32_t result;
+    bool Z = true;
+
+    uint32_t sgn = bits(op, 63);
+    int32_t exp  = bits(op, 62, 52);
+    uint64_t mnt = bits(op, 51, 0);
+
+    if (exp == 0) {
+        if (mnt != 0) {
+           if (fpscr.fz) {
+                flags |= FPLIB_IDC;
+            } else {
+                flags |= FPLIB_IXC;
+                Z = 0;
+            }
+        }
+        result = 0;
+    } else if (exp == 0x7ff) {
+        flags |= FPLIB_IOC;
+        result = 0;
+        Z = 0;
+    } else {
+        mnt |= 1ULL << FP64_MANT_BITS;
+        int mnt_shft = exp - FP64_EXP_BIAS - 52;
+        bool err = true;
+
+        if (abs(mnt_shft) >= FP64_BITS) {
+            result = 0;
+            Z = 0;
+        } else if (mnt_shft >= 0) {
+            result = lsl64(mnt, mnt_shft);
+        } else if (mnt_shft < 0) {
+            err = lsl64(mnt, mnt_shft+FP64_BITS) != 0;
+            result = lsr64(mnt, abs(mnt_shft));
+        }
+        uint64_t max_result = (1UL << (FP32_BITS - 1)) -!sgn;
+        if ((exp - FP64_EXP_BIAS) > 31 || result > max_result) {
+                flags |= FPLIB_IOC;
+                Z = false;
+        } else if (err) {
+                flags |= FPLIB_IXC;
+                Z = false;
+        }
+        result =  sgn ? -result : result;
+    }
+    if (sgn == 1 && result == 0)
+        Z = false;
+
+    if (is64) {
+        nz = Z? 0x1: 0x0;
+    } else {
+        fpscr.n = 0;
+        fpscr.z = (int)Z;
+        fpscr.c = 0;
+        fpscr.v = 0;
+    }
+
+    set_fpscr0(fpscr, flags);
+    return result;
+}
+
 template <>
 uint64_t
 fplibFPToFixed(uint16_t op, int fbits, bool u, FPRounding rounding,
diff --git a/src/arch/arm/insts/fplib.hh b/src/arch/arm/insts/fplib.hh
index d3d7790..a90999d 100644
--- a/src/arch/arm/insts/fplib.hh
+++ b/src/arch/arm/insts/fplib.hh
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2012-2013, 2017-2018 ARM Limited
+ * Copyright (c) 2020 Metempsy Technology Consulting
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -174,6 +175,8 @@
 /** Foating-point value for default NaN. */
 template <class T>
 T fplibDefaultNaN();
+/** Floating-point  JS convert to a signed integer, with rounding to zero. */
+uint32_t fplibFPToFixedJS(uint64_t op, FPSCR &fpscr, bool Is64, uint8_t &nz);
 
 /* Function specializations... */
 template <>
diff --git a/src/arch/arm/isa/formats/aarch64.isa b/src/arch/arm/isa/formats/aarch64.isa
index 55959f5..76c7fd5 100644
--- a/src/arch/arm/isa/formats/aarch64.isa
+++ b/src/arch/arm/isa/formats/aarch64.isa
@@ -2790,6 +2790,8 @@
                             if (rmode != 0)
                                 return new Unknown64(machInst);
                             return new FmovRegCoreW(machInst, rd, rn);
+                          case 2:
+                            return new FJcvtFpSFixedDW(machInst, rd, rn);
                           case 3: // FMOV Xd = Dn
                             if (rmode != 0)
                                 return new Unknown64(machInst);
diff --git a/src/arch/arm/isa/formats/fp.isa b/src/arch/arm/isa/formats/fp.isa
index 133f918..42f0ee8 100644
--- a/src/arch/arm/isa/formats/fp.isa
+++ b/src/arch/arm/isa/formats/fp.isa
@@ -2761,6 +2761,14 @@
                         return new VcvtSIntFpD(machInst, vd, vm);
                     }
                 }
+              case 0x9:
+                if (bits(machInst, 31, 28) != 0xF
+                    && bits(machInst, 27, 23) == 0x1D) {
+                    vd = (IntRegIndex)(bits(machInst, 22) |
+                         (bits(machInst, 15, 12) << 1));
+                    return new VjcvtSFixedFpD(machInst, vd, vm);
+                }
+                break;
               case 0xa:
                 {
                     const bool half = (bits(machInst, 7) == 0);
diff --git a/src/arch/arm/isa/insts/fp.isa b/src/arch/arm/isa/insts/fp.isa
index df4d583..5e6a0a6 100644
--- a/src/arch/arm/isa/insts/fp.isa
+++ b/src/arch/arm/isa/insts/fp.isa
@@ -977,6 +977,24 @@
     decoder_output += FpRegRegOpConstructor.subst(vcvtSIntFpDIop);
     exec_output += PredOpExecute.subst(vcvtSIntFpDIop);
 
+    vjcvtSFixedFpDCode = vfpEnabledCheckCode + '''
+        FPSCR fpscr = (FPSCR) FpscrExc;
+        VfpSavedState state = prepFpState(fpscr.rMode);
+        uint64_t cOp1 = ((uint64_t)FpOp1P0_uw | ((uint64_t)FpOp1P1_uw << 32));
+        uint8_t nz;
+        FpDest_uw = fplibFPToFixedJS(cOp1, fpscr, false, nz);
+        finishVfp(fpscr, state, fpscr.fz);
+        FpCondCodes = fpscr & FpCondCodesMask;
+        FpscrExc = fpscr;
+    '''
+    vjcvtSFixedFpDIop = InstObjParams("vjcvt", "VjcvtSFixedFpD", "FpRegRegOp",
+                                     { "code": vjcvtSFixedFpDCode,
+                                       "predicate_test": predicateTest,
+                                       "op_class": "SimdFloatCvtOp" }, [])
+    header_output += FpRegRegOpDeclare.subst(vjcvtSFixedFpDIop);
+    decoder_output += FpRegRegOpConstructor.subst(vjcvtSFixedFpDIop);
+    exec_output += PredOpExecute.subst(vjcvtSFixedFpDIop);
+
     vcvtFpUIntSRCode = vfpEnabledCheckCode + '''
         FPSCR fpscr = (FPSCR) FpscrExc;
         VfpSavedState state = prepFpState(fpscr.rMode);
diff --git a/src/arch/arm/isa/insts/fp64.isa b/src/arch/arm/isa/insts/fp64.isa
index 7decbac..409780a 100644
--- a/src/arch/arm/isa/insts/fp64.isa
+++ b/src/arch/arm/isa/insts/fp64.isa
@@ -837,6 +837,29 @@
         decoder_output += AA64FpRegRegImmOpConstructor.subst(fcvtFpFixedIop);
         exec_output    += BasicExecute.subst(fcvtFpFixedIop);
 
+    def buildFpJsCvtFixedOp():
+        global header_output, decoder_output, exec_output
+
+        fcvtFpFixedCode = vfp64EnabledCheckCode + '''
+            FPSCR fpscr = (FPSCR) FpscrExc;
+            uint64_t cOp1 = AA64FpOp1P0_uw | (uint64_t)AA64FpOp1P1_uw << 32;
+            uint8_t nz;
+            WDest = fplibFPToFixedJS(cOp1, fpscr, true, nz);
+            CondCodesNZ = nz;
+            CondCodesV = 0;
+            CondCodesC = 0;
+            FpscrExc = fpscr;
+        ''';
+
+        instName = "FJcvtFpSFixedDW"
+        mnem = "fjcvtzs"
+        fcvtFpFixedIop = InstObjParams(mnem, instName, "FpRegRegOp",
+                                       { "code": fcvtFpFixedCode,
+                                         "op_class": "FloatCvtOp" }, [])
+        header_output  += FpRegRegOpDeclare.subst(fcvtFpFixedIop);
+        decoder_output += AA64FpRegRegOpConstructor.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
@@ -886,6 +909,7 @@
             for isSigned in True, False:
                 buildFpCvtFixedOp(isSigned, isDouble, isXReg)
                 buildFixedCvtFpOp(isSigned, isDouble, isXReg)
+    buildFpJsCvtFixedOp();
 }};
 
 let {{