arch-arm: Add support for SVE RDFFR(S), WRFFR and SETFFR

Change-Id: I615723d82752c444e513d8917c2eeba9cdf75514
Signed-off-by: Giacomo Gabrielli <giacomo.gabrielli@arm.com>
diff --git a/src/arch/arm/insts/sve.cc b/src/arch/arm/insts/sve.cc
index fb7218a..4d1bb6d 100644
--- a/src/arch/arm/insts/sve.cc
+++ b/src/arch/arm/insts/sve.cc
@@ -617,7 +617,7 @@
 }
 
 std::string
-SvePredUnaryOp::generateDisassembly(Addr pc,
+SvePredUnaryWImplicitSrcOp::generateDisassembly(Addr pc,
         const SymbolTable *symtab) const
 {
     std::stringstream ss;
@@ -627,6 +627,38 @@
 }
 
 std::string
+SvePredUnaryWImplicitSrcPredOp::generateDisassembly(Addr pc,
+        const SymbolTable *symtab) const
+{
+    std::stringstream ss;
+    printMnemonic(ss, "", false);
+    printReg(ss, RegId(PredRegClass, dest));
+    ccprintf(ss, ", ");
+    printReg(ss, RegId(PredRegClass, gp));
+    ccprintf(ss, "/z, ");
+    return ss.str();
+}
+
+std::string
+SvePredUnaryWImplicitDstOp::generateDisassembly(Addr pc,
+        const SymbolTable *symtab) const
+{
+    std::stringstream ss;
+    printMnemonic(ss, "", false);
+    printReg(ss, RegId(PredRegClass, op1));
+    return ss.str();
+}
+
+std::string
+SveWImplicitSrcDstOp::generateDisassembly(Addr pc,
+        const SymbolTable *symtab) const
+{
+    std::stringstream ss;
+    printMnemonic(ss, "", false);
+    return ss.str();
+}
+
+std::string
 SveBinImmUnpredDestrOp::generateDisassembly(Addr pc,
         const SymbolTable *symtab) const
 {
diff --git a/src/arch/arm/insts/sve.hh b/src/arch/arm/insts/sve.hh
index b49a6d2..2417211 100644
--- a/src/arch/arm/insts/sve.hh
+++ b/src/arch/arm/insts/sve.hh
@@ -646,19 +646,57 @@
     std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
 };
 
-/// SVE unary predicate instructions
-class SvePredUnaryOp : public ArmStaticInst {
+/// SVE unary predicate instructions with implicit source operand
+class SvePredUnaryWImplicitSrcOp : public ArmStaticInst {
   protected:
     IntRegIndex dest;
 
-    SvePredUnaryOp(const char* mnem, ExtMachInst _machInst, OpClass __opClass,
-                IntRegIndex _dest) :
+    SvePredUnaryWImplicitSrcOp(const char* mnem, ExtMachInst _machInst,
+                               OpClass __opClass, IntRegIndex _dest) :
         ArmStaticInst(mnem, _machInst, __opClass),
         dest(_dest)
     {}
     std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
 };
 
+/// SVE unary predicate instructions, predicated, with implicit source operand
+class SvePredUnaryWImplicitSrcPredOp : public ArmStaticInst {
+  protected:
+    IntRegIndex dest;
+    IntRegIndex gp;
+
+    SvePredUnaryWImplicitSrcPredOp(const char* mnem, ExtMachInst _machInst,
+                                   OpClass __opClass, IntRegIndex _dest,
+                                   IntRegIndex _gp) :
+        ArmStaticInst(mnem, _machInst, __opClass),
+        dest(_dest), gp(_gp)
+    {}
+    std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+};
+
+/// SVE unary predicate instructions with implicit destination operand
+class SvePredUnaryWImplicitDstOp : public ArmStaticInst {
+  protected:
+    IntRegIndex op1;
+
+    SvePredUnaryWImplicitDstOp(const char* mnem, ExtMachInst _machInst,
+                               OpClass __opClass, IntRegIndex _op1) :
+        ArmStaticInst(mnem, _machInst, __opClass),
+        op1(_op1)
+    {}
+    std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+};
+
+/// SVE unary predicate instructions with implicit destination operand
+class SveWImplicitSrcDstOp : public ArmStaticInst {
+  protected:
+    SveWImplicitSrcDstOp(const char* mnem, ExtMachInst _machInst,
+                         OpClass __opClass) :
+        ArmStaticInst(mnem, _machInst, __opClass)
+    {}
+    std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+};
+
 /// SVE vector - immediate binary operation
 class SveBinImmUnpredDestrOp : public ArmStaticInst {
   protected:
diff --git a/src/arch/arm/isa/formats/sve_2nd_level.isa b/src/arch/arm/isa/formats/sve_2nd_level.isa
index b80b65d..b32ad38 100644
--- a/src/arch/arm/isa/formats/sve_2nd_level.isa
+++ b/src/arch/arm/isa/formats/sve_2nd_level.isa
@@ -1,4 +1,3 @@
-// Copyright (c) 2017 ARM Limited
 // All rights reserved
 //
 // The license below extends only to copyright in the software and shall
@@ -1624,13 +1623,26 @@
     StaticInstPtr
     decodeSveReadPredFromFFRPred(ExtMachInst machInst)
     {
-        return new Unknown64(machInst);
+        if (bits(machInst, 23)) {
+            return new Unknown64(machInst);
+        }
+        IntRegIndex pd = (IntRegIndex)(uint8_t) bits(machInst, 3, 0);
+        IntRegIndex pg = (IntRegIndex)(uint8_t) bits(machInst, 8, 5);
+        if (bits(machInst, 22)) {
+            return new SveRdffrsPred(machInst, pd, pg);
+        } else {
+            return new SveRdffrPred(machInst, pd, pg);
+        }
     }  // decodeSveReadPredFromFFRPred
 
     StaticInstPtr
     decodeSveReadPredFromFFRUnpred(ExtMachInst machInst)
     {
-        return new Unknown64(machInst);
+        if (bits(machInst, 23, 22) != 0) {
+            return new Unknown64(machInst);
+        }
+        IntRegIndex pd = (IntRegIndex)(uint8_t) bits(machInst, 3, 0);
+        return new SveRdffrUnpred(machInst, pd);
     }  // decodeSveReadPredFromFFRUnpred
 
     StaticInstPtr
@@ -1807,11 +1819,11 @@
                         bits(machInst, 4, 0) == 0x0) {
                     uint8_t opc = bits(machInst, 18, 16);
                     if (opc == 0x0) {
-                        // TODO: WRFFR
-                        return new NopInst(machInst);
+                        IntRegIndex pn = (IntRegIndex)(uint8_t)
+                            bits(machInst, 8, 5);
+                        return new SveWrffr(machInst, pn);
                     } else if (opc == 0x4 && bits(machInst, 8, 5) == 0x0) {
-                        // TODO: SETFFR
-                        return new NopInst(machInst);
+                        return new SveSetffr(machInst);
                     }
                 }
                 break;
diff --git a/src/arch/arm/isa/insts/sve.isa b/src/arch/arm/isa/insts/sve.isa
index 9aaffc9..b5db2a9 100644
--- a/src/arch/arm/isa/insts/sve.isa
+++ b/src/arch/arm/isa/insts/sve.isa
@@ -2459,18 +2459,48 @@
             substDict = {'targs': type, 'class_name': 'Sve' + Name}
             exec_output += SveOpExecDeclare.subst(substDict)
 
-    # Generate definition for SVE PFALSE instruction
-    def svePfalseInst(name, Name, opClass, decoder = 'Generic'):
+    # Generate definition for unary SVE predicate instructions with implicit
+    # source operand (PFALSE, RDFFR(S))
+    def svePredUnaryWImplicitSrcInst(name, Name, opClass, op,
+            predType=PredType.NONE, isFlagSetting=False, decoder='Generic'):
         global header_output, exec_output, decoders
-        code = sveEnabledCheckCode + '''
-        PDest_ub[0] = 0;
-        destPred.reset();'''
+        code = sveEnabledCheckCode + op
+        if isFlagSetting:
+            code += '''
+        CondCodesNZ = (destPred.firstActive(GpOp, eCount) << 1) |
+                      destPred.noneActive(GpOp, eCount);
+        CondCodesC = !destPred.lastActive(GpOp, eCount);
+        CondCodesV = 0;'''
         extraPrologCode = '''
-        auto& destPred = PDest;'''
-        iop = InstObjParams(name, 'Sve' + Name, 'SvePredUnaryOp',
+        auto& destPred M5_VAR_USED = PDest;'''
+        baseClass = ('SvePredUnaryWImplicitSrcOp' if predType == PredType.NONE
+                     else 'SvePredUnaryWImplicitSrcPredOp')
+        iop = InstObjParams(name, 'Sve' + Name, baseClass,
                 {'code': code, 'op_class': opClass}, [])
         iop.snippets['code'] = extraPrologCode + iop.snippets['code']
-        header_output += SvePredicateUnaryOpDeclare.subst(iop)
+        if predType == PredType.NONE:
+            header_output += SvePredUnaryOpWImplicitSrcDeclare.subst(iop)
+        else:
+            header_output += SvePredUnaryPredOpWImplicitSrcDeclare.subst(iop)
+        exec_output += SveNonTemplatedOpExecute.subst(iop)
+
+    # Generate definition for SVE instructions writing to the FFR (SETFFR,
+    # WRFFR)
+    def svePredWriteFfrInst(name, Name, opClass, op, isSetFfr,
+            decoder='Generic'):
+        global header_output, exec_output, decoders
+        code = sveEnabledCheckCode + op
+        extraPrologCode = '''
+        auto& destPred M5_VAR_USED = Ffr;'''
+        baseClass = ('SveWImplicitSrcDstOp' if isSetFfr
+                     else 'SvePredUnaryWImplicitDstOp')
+        iop = InstObjParams(name, 'Sve' + Name, baseClass,
+                {'code': code, 'op_class': opClass}, [])
+        iop.snippets['code'] = extraPrologCode + iop.snippets['code']
+        if isSetFfr:
+            header_output += SveOpWImplicitSrcDstDeclare.subst(iop)
+        else:
+            header_output += SvePredUnaryOpWImplicitDstDeclare.subst(iop)
         exec_output += SveNonTemplatedOpExecute.subst(iop)
 
     # Generate definition for SVE Ext instruction
@@ -3509,7 +3539,12 @@
     sveAssocReducInst('orv', 'Orv', 'SimdReduceAluOp', unsignedTypes,
                       orvCode, '0')
     # PFALSE
-    svePfalseInst('pfalse', 'Pfalse', 'SimdPredAluOp')
+    pfalseCode = '''
+        PDest_ub[0] = 0;
+        destPred.reset();
+    '''
+    svePredUnaryWImplicitSrcInst('pfalse', 'Pfalse', 'SimdPredAluOp',
+            pfalseCode)
     # PFIRST
     svePFirstInst('pfirst', 'Pfirst', 'SimdPredAluOp')
     # PNEXT
@@ -3531,6 +3566,30 @@
         destElem = reverseBits(srcElem1);'''
     sveUnaryInst('rbit', 'Rbit', 'SimdAluOp', unsignedTypes, rbitCode,
             predType=PredType.MERGE, srcRegType=SrcRegType.Vector)
+    # RDFFR, RDFFRS (predicated)
+    rdffrPredCode = '''
+        unsigned eCount = ArmStaticInst::getCurSveVecLen<uint8_t>(
+                xc->tcBase());
+        for (unsigned i = 0; i < eCount; i++) {
+            if (GpOp_ub[i]) {
+                PDest_ub[i] = Ffr_ub[i];
+            } else {
+                PDest_ub[i] = false;
+            }
+        }'''
+    svePredUnaryWImplicitSrcInst('rdffr', 'RdffrPred', 'SimdPredAluOp',
+            rdffrPredCode, PredType.ZERO, False)
+    svePredUnaryWImplicitSrcInst('rdffrs', 'RdffrsPred', 'SimdPredAluOp',
+            rdffrPredCode, PredType.ZERO, True)
+    # RDFFR (unpredicated)
+    rdffrUnpredCode = '''
+        unsigned eCount = ArmStaticInst::getCurSveVecLen<uint8_t>(
+                xc->tcBase());
+        for (unsigned i = 0; i < eCount; i++) {
+            PDest_ub[i] = Ffr_ub[i];
+        }'''
+    svePredUnaryWImplicitSrcInst('rdffr', 'RdffrUnpred', 'SimdPredAluOp',
+            rdffrUnpredCode)
     # RDVL
     rdvlCode = sveEnabledCheckCode + '''
         unsigned eCount = ArmStaticInst::getCurSveVecLen<uint8_t>(
@@ -3618,6 +3677,11 @@
     # SEL (vectors)
     sveBinInst('sel', 'Sel', 'SimdAluOp', unsignedTypes, selCode,
                PredType.SELECT, False)
+    # SETFFR
+    setffrCode = '''
+        Ffr_ub[0] = true;
+        destPred.set();'''
+    svePredWriteFfrInst('setffr', 'Setffr', 'SimdPredAluOp', setffrCode, True)
     # SMAX (immediate)
     maxCode = 'destElem = (srcElem1 > srcElem2) ? srcElem1 : srcElem2;'
     sveWideImmInst('smax', 'SmaxImm', 'SimdCmpOp', signedTypes, maxCode)
@@ -4169,6 +4233,14 @@
     # WHILELT (64-bit)
     sveWhileInst('whilelt', 'Whilelt64', 'SimdCmpOp', signedTypes,
                  whileLTCode, SrcSize.Src64bit)
+    # WRFFR
+    wrffrCode = '''
+        unsigned eCount = ArmStaticInst::getCurSveVecLen<uint8_t>(
+                xc->tcBase());
+        for (unsigned i = 0; i < eCount; i++) {
+            Ffr_ub[i] = POp1_ub[i];
+        }'''
+    svePredWriteFfrInst('wrffr', 'Wrffr', 'SimdPredAluOp', wrffrCode, False)
     # ZIP1, ZIP2 (predicates)
     zipPredIterCode = '''
         constexpr unsigned sz = sizeof(Element);
diff --git a/src/arch/arm/isa/operands.isa b/src/arch/arm/isa/operands.isa
index f4880fb..bc4d057 100644
--- a/src/arch/arm/isa/operands.isa
+++ b/src/arch/arm/isa/operands.isa
@@ -531,6 +531,7 @@
     'POp1': predReg('op1'),
     'POp2': predReg('op2'),
     'PDest': predReg('dest'),
+    'Ffr': predReg('PREDREG_FFR'),
 
     #Abstracted control reg operands
     'MiscDest': cntrlReg('dest'),
diff --git a/src/arch/arm/isa/templates/sve.isa b/src/arch/arm/isa/templates/sve.isa
index a27bfdc..6edcb8b 100644
--- a/src/arch/arm/isa/templates/sve.isa
+++ b/src/arch/arm/isa/templates/sve.isa
@@ -778,7 +778,7 @@
 };
 }};
 
-def template SvePredicateUnaryOpDeclare {{
+def template SvePredUnaryOpWImplicitSrcDeclare {{
 class %(class_name)s : public %(base_class)s
 {
   public:
@@ -792,6 +792,48 @@
 };
 }};
 
+def template SvePredUnaryPredOpWImplicitSrcDeclare {{
+class %(class_name)s : public %(base_class)s
+{
+  public:
+    %(class_name)s(ExtMachInst machInst, IntRegIndex _dest, IntRegIndex _gp)
+        : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, _dest, _gp)
+    {
+        %(constructor)s;
+    }
+
+    %(BasicExecDeclare)s
+};
+}};
+
+def template SvePredUnaryOpWImplicitDstDeclare {{
+class %(class_name)s : public %(base_class)s
+{
+  public:
+    %(class_name)s(ExtMachInst machInst, IntRegIndex _op1)
+        : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, _op1)
+    {
+        %(constructor)s;
+    }
+
+    %(BasicExecDeclare)s
+};
+}};
+
+def template SveOpWImplicitSrcDstDeclare {{
+class %(class_name)s : public %(base_class)s
+{
+  public:
+    %(class_name)s(ExtMachInst machInst)
+        : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s)
+    {
+        %(constructor)s;
+    }
+
+    %(BasicExecDeclare)s
+};
+}};
+
 def template SveWideningUnaryOpExecute {{
     template <class SElement, class DElement>
     Fault %(class_name)s<SElement, DElement>::execute(CPU_EXEC_CONTEXT *xc,
diff --git a/src/arch/arm/registers.hh b/src/arch/arm/registers.hh
index c23e51d..80bbfa8 100644
--- a/src/arch/arm/registers.hh
+++ b/src/arch/arm/registers.hh
@@ -99,7 +99,8 @@
 const int NumFloatRegs = NumFloatV8ArchRegs + NumFloatSpecialRegs;
 const int NumVecRegs = NumVecV8ArchRegs + NumVecSpecialRegs;
 const int NumCCRegs = NUM_CCREGS;
-const int NumPredRegs = 16;
+const int NumPredRegs = 17;  // P0-P15, FFR
+const int PREDREG_FFR = 16;
 const int NumMiscRegs = NUM_MISCREGS;
 
 #define ISA_HAS_CC_REGS
diff --git a/src/arch/generic/pred_reg.hh b/src/arch/generic/pred_reg.hh
index 9c363ee..a67ba35 100644
--- a/src/arch/generic/pred_reg.hh
+++ b/src/arch/generic/pred_reg.hh
@@ -94,6 +94,11 @@
     typename std::enable_if<Condition, void>::type
     reset() { container.reset(); }
 
+    /// Reset the register to an all-true value.
+    template<bool Condition = !Const>
+    typename std::enable_if<Condition, void>::type
+    set() { container.set(); }
+
     template<bool Condition = !Const>
     typename std::enable_if<Condition, MyClass&>::type
     operator=(const MyClass& that)
@@ -268,6 +273,13 @@
         container.fill(false);
     }
 
+    /// Sets the predicate register to an all-true value.
+    void
+    set()
+    {
+        container.fill(true);
+    }
+
     /// Equality operator, required to compare thread contexts.
     template<size_t N2, bool P2>
     inline bool