arm: extend MiscReg metadata structures

Implement proper handling of RES0/RES1 and RAZ/RAO bitfields.

Change-Id: I344c32c3fb1d142acfb0521ba3590ddd2b1f5360
Signed-off-by: Curtis Dunham <Curtis.Dunham@arm.com>
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Reviewed-by: Jack Travaglini <giacomo.travaglini@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/6802
Maintainer: Andreas Sandberg <andreas.sandberg@arm.com>
diff --git a/src/arch/arm/isa.cc b/src/arch/arm/isa.cc
index 6a803fe..a9648d2 100644
--- a/src/arch/arm/isa.cc
+++ b/src/arch/arm/isa.cc
@@ -205,6 +205,9 @@
     InitReg(MISCREG_PMXEVCNTR_EL0).mapsTo(MISCREG_PMXEVCNTR);
     InitReg(MISCREG_PMXEVTYPER_EL0).mapsTo(MISCREG_PMXEVTYPER);
 
+    InitReg(MISCREG_SCR).res0(0xff40)  // [31:16], [6]
+                        .res1(0x0030); // [5:4]
+
     // from ARM DDI 0487A.i, template text
     // "AArch64 System register ___ can be mapped to
     //  AArch32 System register ___, but this is not
@@ -492,10 +495,22 @@
 {
     assert(misc_reg < NumMiscRegs);
 
-    auto regs = getMiscIndices(misc_reg);
-    int lower = regs.first, upper = regs.second;
-    return !upper ? miscRegs[lower] : ((miscRegs[lower] & mask(32))
-                                      |(miscRegs[upper] << 32));
+    const auto &reg = lookUpMiscReg[misc_reg]; // bit masks
+    const auto &map = getMiscIndices(misc_reg);
+    int lower = map.first, upper = map.second;
+    // NB!: apply architectural masks according to desired register,
+    // despite possibly getting value from different (mapped) register.
+    auto val = !upper ? miscRegs[lower] : ((miscRegs[lower] & mask(32))
+                                          |(miscRegs[upper] << 32));
+    if (val & reg.res0()) {
+        DPRINTF(MiscRegs, "Reading MiscReg %s with set res0 bits: %#x\n",
+                miscRegName[misc_reg], val & reg.res0());
+    }
+    if ((val & reg.res1()) != reg.res1()) {
+        DPRINTF(MiscRegs, "Reading MiscReg %s with clear res1 bits: %#x\n",
+                miscRegName[misc_reg], (val & reg.res1()) ^ reg.res1());
+    }
+    return (val & ~reg.raz()) | reg.rao(); // enforce raz/rao
 }
 
 
@@ -814,17 +829,20 @@
 {
     assert(misc_reg < NumMiscRegs);
 
-    auto regs = getMiscIndices(misc_reg);
-    int lower = regs.first, upper = regs.second;
+    const auto &reg = lookUpMiscReg[misc_reg]; // bit masks
+    const auto &map = getMiscIndices(misc_reg);
+    int lower = map.first, upper = map.second;
+
+    auto v = (val & ~reg.wi()) | reg.rao();
     if (upper > 0) {
-        miscRegs[lower] = bits(val, 31, 0);
-        miscRegs[upper] = bits(val, 63, 32);
+        miscRegs[lower] = bits(v, 31, 0);
+        miscRegs[upper] = bits(v, 63, 32);
         DPRINTF(MiscRegs, "Writing to misc reg %d (%d:%d) : %#x\n",
-                misc_reg, lower, upper, val);
+                misc_reg, lower, upper, v);
     } else {
-        miscRegs[lower] = val;
+        miscRegs[lower] = v;
         DPRINTF(MiscRegs, "Writing to misc reg %d (%d) : %#x\n",
-                misc_reg, lower, val);
+                misc_reg, lower, v);
     }
 }
 
diff --git a/src/arch/arm/isa.hh b/src/arch/arm/isa.hh
index 2241be7..d903ed0 100644
--- a/src/arch/arm/isa.hh
+++ b/src/arch/arm/isa.hh
@@ -89,10 +89,26 @@
         bool haveLargeAsid64;
         uint8_t physAddrRange64;
 
-        /** Register translation entry used in lookUpMiscReg */
+        /** MiscReg metadata **/
         struct MiscRegLUTEntry {
             uint32_t lower;  // Lower half mapped to this register
             uint32_t upper;  // Upper half mapped to this register
+            uint64_t _reset; // value taken on reset (i.e. initialization)
+            uint64_t _res0;  // reserved
+            uint64_t _res1;  // reserved
+            uint64_t _raz;   // read as zero (fixed at 0)
+            uint64_t _rao;   // read as one (fixed at 1)
+          public:
+            MiscRegLUTEntry() :
+              lower(0), upper(0),
+              _reset(0), _res0(0), _res1(0), _raz(0), _rao(0) {}
+            uint64_t reset() const { return _reset; }
+            uint64_t res0()  const { return _res0; }
+            uint64_t res1()  const { return _res1; }
+            uint64_t raz()   const { return _raz; }
+            uint64_t rao()   const { return _rao; }
+            // raz/rao implies writes ignored
+            uint64_t wi()    const { return _raz | _rao; }
         };
 
         /** Metadata table accessible via the value of the register */
@@ -107,6 +123,22 @@
                 entry.upper = u;
                 return *this;
             }
+            chain res0(uint64_t mask) const {
+                entry._res0 = mask;
+                return *this;
+            }
+            chain res1(uint64_t mask) const {
+                entry._res1 = mask;
+                return *this;
+            }
+            chain raz(uint64_t mask) const {
+                entry._raz  = mask;
+                return *this;
+            }
+            chain rao(uint64_t mask) const {
+                entry._rao  = mask;
+                return *this;
+            }
             MiscRegLUTEntryInitializer(struct MiscRegLUTEntry &e)
                 : entry(e)
               {}