arch-arm: Rewrite MSR immediate instruction class

MSR <pstatefield>, #imm is used for setting a PSTATE field using an
immediate. Current implementation has the following flaws:

* There is no base MSR immediate definition: all the existing
PSTATE fields have a different class definition
* Those implementation make use of a generic data64 base class
which results in a wrong disassembly (pstate register is printed as an
integer register).

This patch is fixing this by defining a new base class (MiscRegImmOp64)
and new related templates. In this way, we aim to ease addition of new
PSTATE fields (in ARMv8.x)

Change-Id: I71b630ff32abe1b105bbb3ab5781c6589b67d419
Signed-off-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/19728
Maintainer: Andreas Sandberg <andreas.sandberg@arm.com>
Tested-by: kokoro <noreply+kokoro@google.com>
diff --git a/src/arch/arm/insts/misc64.cc b/src/arch/arm/insts/misc64.cc
index 423aaca..cf625eb 100644
--- a/src/arch/arm/insts/misc64.cc
+++ b/src/arch/arm/insts/misc64.cc
@@ -35,6 +35,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * Authors: Gabe Black
+ *          Giacomo Travaglini
  */
 
 #include "arch/arm/insts/misc64.hh"
@@ -321,6 +322,27 @@
     return trap_to_mon;
 }
 
+RegVal
+MiscRegImmOp64::miscRegImm() const
+{
+    if (dest == MISCREG_SPSEL) {
+        return imm & 0x1;
+    } else {
+        panic("Not a valid PSTATE field register\n");
+    }
+}
+
+std::string
+MiscRegImmOp64::generateDisassembly(Addr pc, const SymbolTable *symtab) const
+{
+    std::stringstream ss;
+    printMnemonic(ss);
+    printMiscReg(ss, dest);
+    ss << ", ";
+    ccprintf(ss, "#0x%x", imm);
+    return ss.str();
+}
+
 std::string
 MiscRegRegImmOp64::generateDisassembly(
     Addr pc, const SymbolTable *symtab) const
diff --git a/src/arch/arm/insts/misc64.hh b/src/arch/arm/insts/misc64.hh
index f70344b..741b7b5 100644
--- a/src/arch/arm/insts/misc64.hh
+++ b/src/arch/arm/insts/misc64.hh
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2013,2017-2018 ARM Limited
+ * Copyright (c) 2011-2013,2017-2019 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -35,6 +35,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * Authors: Gabe Black
+ *          Giacomo Travaglini
  */
 
 #ifndef __ARCH_ARM_INSTS_MISC64_HH__
@@ -142,6 +143,30 @@
 
 };
 
+class MiscRegImmOp64 : public MiscRegOp64
+{
+  protected:
+    MiscRegIndex dest;
+    uint32_t imm;
+
+    MiscRegImmOp64(const char *mnem, ExtMachInst _machInst,
+                   OpClass __opClass, MiscRegIndex _dest,
+                   uint32_t _imm) :
+        MiscRegOp64(mnem, _machInst, __opClass, false),
+        dest(_dest), imm(_imm)
+    {}
+
+    /** Returns the "register view" of the immediate field.
+     * as if it was a MSR PSTATE REG instruction.
+     * This means basically shifting and masking depending on
+     * which PSTATE field is being set/cleared.
+     */
+    RegVal miscRegImm() const;
+
+    std::string generateDisassembly(
+            Addr pc, const SymbolTable *symtab) const override;
+};
+
 class MiscRegRegImmOp64 : public MiscRegOp64
 {
   protected:
diff --git a/src/arch/arm/isa/formats/aarch64.isa b/src/arch/arm/isa/formats/aarch64.isa
index 15cbe90..144ff88 100644
--- a/src/arch/arm/isa/formats/aarch64.isa
+++ b/src/arch/arm/isa/formats/aarch64.isa
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2018 ARM Limited
+// Copyright (c) 2011-2019 ARM Limited
 // All rights reserved
 //
 // The license below extends only to copyright in the software and shall
@@ -389,28 +389,21 @@
                             return new Unknown64(machInst);
                         }
                     } else if (crn == 0x4) {
-                        // MSR immediate
+                        // MSR immediate: moving immediate value to selected
+                        // bits of the PSTATE
                         switch (op1 << 3 | op2) {
                           case 0x5:
                             // SP
-                            return new MsrSP64(machInst,
-                                               (IntRegIndex) MISCREG_SPSEL,
-                                               INTREG_ZERO,
-                                               crm & 0x1);
+                            return new MsrImm64(
+                                machInst, MISCREG_SPSEL, crm);
                           case 0x1e:
                             // DAIFSet
-                            return new MsrDAIFSet64(
-                                machInst,
-                                (IntRegIndex) MISCREG_DAIF,
-                                INTREG_ZERO,
-                                crm);
+                            return new MsrImmDAIFSet64(
+                                machInst, MISCREG_DAIF, crm);
                           case 0x1f:
                             // DAIFClr
-                            return new MsrDAIFClr64(
-                                machInst,
-                                (IntRegIndex) MISCREG_DAIF,
-                                INTREG_ZERO,
-                                crm);
+                            return new MsrImmDAIFClr64(
+                                machInst, MISCREG_DAIF, crm);
                           default:
                             return new Unknown64(machInst);
                         }
diff --git a/src/arch/arm/isa/insts/data64.isa b/src/arch/arm/isa/insts/data64.isa
index d348190..b3e03d6 100644
--- a/src/arch/arm/isa/insts/data64.isa
+++ b/src/arch/arm/isa/insts/data64.isa
@@ -1,6 +1,6 @@
 // -*- mode:c++ -*-
 
-// Copyright (c) 2011-2013, 2016-2018 ARM Limited
+// Copyright (c) 2011-2013, 2016-2019 ARM Limited
 // All rights reserved
 //
 // The license below extends only to copyright in the software and shall
@@ -509,45 +509,43 @@
     exec_output += DCStore64InitiateAcc.subst(msrDCIVACIop);
     exec_output += Store64CompleteAcc.subst(msrDCIVACIop);
 
+    def buildMsrImmInst(mnem, inst_name, code):
+        global header_output, decoder_output, exec_output
+        msrImmPermission = '''
+            if (!canWriteAArch64SysReg(
+                    (MiscRegIndex) xc->tcBase()->flattenRegId(
+                       RegId(MiscRegClass, dest)).index(),
+                    Scr64, Cpsr, xc->tcBase())) {
+                return std::make_shared<UndefinedInstruction>(
+                                machInst, 0, EC_TRAPPED_MSR_MRS_64,
+                                mnemonic);
+            }
 
-    buildDataXImmInst("msrSP", '''
-        if (!canWriteAArch64SysReg(
-                (MiscRegIndex) xc->tcBase()->flattenRegId(
-                   RegId(MiscRegClass, dest)).index(),
-                Scr64, Cpsr, xc->tcBase())) {
-            return std::make_shared<UndefinedInstruction>(machInst, false,
-                                                          mnemonic);
-        }
-        MiscDest_ud = imm;
-    ''', optArgs = ["IsSerializeAfter", "IsNonSpeculative"])
+        '''
+        msrIop = InstObjParams("msr", inst_name, "MiscRegImmOp64",
+                               msrImmPermission + code,
+                               ["IsSerializeAfter", "IsNonSpeculative"])
+        header_output += MiscRegOp64Declare.subst(msrIop)
+        decoder_output += MiscRegOp64Constructor.subst(msrIop)
+        exec_output += BasicExecute.subst(msrIop)
 
-    buildDataXImmInst("msrDAIFSet", '''
-        if (!canWriteAArch64SysReg(
-                (MiscRegIndex) xc->tcBase()->flattenRegId(
-                   RegId(MiscRegClass, dest)).index(),
-                Scr64, Cpsr, xc->tcBase())) {
-            return std::make_shared<UndefinedInstruction>(
-                            machInst, 0, EC_TRAPPED_MSR_MRS_64,
-                            mnemonic);
-        }
+    buildMsrImmInst("msr", "MsrImm64", '''
+        // Mask and shift immediate (depending on PSTATE field)
+        // before assignment
+        MiscDest_ud = miscRegImm();
+    ''')
+
+    buildMsrImmInst("msr", "MsrImmDAIFSet64", '''
         CPSR cpsr = Cpsr;
         cpsr.daif = cpsr.daif | imm;
         Cpsr = cpsr;
-    ''', optArgs = ["IsSerializeAfter", "IsNonSpeculative"])
+    ''')
 
-    buildDataXImmInst("msrDAIFClr", '''
-        if (!canWriteAArch64SysReg(
-                (MiscRegIndex) xc->tcBase()->flattenRegId(
-                   RegId(MiscRegClass, dest)).index(),
-                Scr64, Cpsr, xc->tcBase())) {
-            return std::make_shared<UndefinedInstruction>(
-                                machInst, 0, EC_TRAPPED_MSR_MRS_64,
-                                mnemonic);
-        }
+    buildMsrImmInst("msr", "MsrImmDAIFClr64", '''
         CPSR cpsr = Cpsr;
         cpsr.daif = cpsr.daif & ~imm;
         Cpsr = cpsr;
-    ''', optArgs = ["IsSerializeAfter", "IsNonSpeculative"])
+    ''')
 
     def buildDataXCompInst(mnem, instType, suffix, code):
         global header_output, decoder_output, exec_output
diff --git a/src/arch/arm/isa/templates/misc64.isa b/src/arch/arm/isa/templates/misc64.isa
index 3c830c8..ed9b4a3 100644
--- a/src/arch/arm/isa/templates/misc64.isa
+++ b/src/arch/arm/isa/templates/misc64.isa
@@ -1,6 +1,6 @@
 // -*- mode:c++ -*-
 
-// Copyright (c) 2011,2017-2018 ARM Limited
+// Copyright (c) 2011,2017-2019 ARM Limited
 // All rights reserved
 //
 // The license below extends only to copyright in the software and shall
@@ -109,6 +109,29 @@
     }
 }};
 
+def template MiscRegOp64Declare {{
+class %(class_name)s : public %(base_class)s
+{
+    public:
+        // Constructor
+        %(class_name)s(ExtMachInst machInst, MiscRegIndex _dest,
+                uint64_t _imm);
+
+        Fault execute(ExecContext *, Trace::InstRecord *) const override;
+};
+}};
+
+def template MiscRegOp64Constructor {{
+    %(class_name)s::%(class_name)s(ExtMachInst machInst,
+                                          MiscRegIndex _dest,
+                                          uint64_t _imm)
+        : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s,
+                         _dest, _imm)
+    {
+        %(constructor)s;
+    }
+}};
+
 def template MiscRegRegOp64Declare {{
 class %(class_name)s : public %(base_class)s
 {