arch-arm: Implement LoadAcquire/StoreRelease in AArch32

This patch is implementing LoadAcquire/StoreRelease instructions in
AArch32, which were added in ARMv8-A only and where not present in
ARMv7.

Change-Id: I5e26459971d0b183a955cd7b0c9c7eaffef453be
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/15817
Maintainer: Andreas Sandberg <andreas.sandberg@arm.com>
diff --git a/src/arch/arm/isa/formats/mem.isa b/src/arch/arm/isa/formats/mem.isa
index 888bbdf..9bc23f6 100644
--- a/src/arch/arm/isa/formats/mem.isa
+++ b/src/arch/arm/isa/formats/mem.isa
@@ -1,6 +1,6 @@
 // -*- mode:c++ -*-
 
-// Copyright (c) 2010 ARM Limited
+// Copyright (c) 2010,2019 ARM Limited
 // All rights reserved
 //
 // The license below extends only to copyright in the software and shall
@@ -225,21 +225,54 @@
         const IntRegIndex rn = (IntRegIndex)(uint32_t)bits(machInst, 19, 16);
         const IntRegIndex rt = (IntRegIndex)(uint32_t)bits(machInst, 15, 12);
         const IntRegIndex rt2 = (IntRegIndex)(uint32_t)bits(machInst, 3, 0);
-        switch (PUBWL) {
-          case 0x18:
+
+        const auto type_L = bits(machInst, 22, 20);
+        const auto ex_ord = bits(machInst, 9, 8);
+        const auto dec_fields = (type_L << 2) | ex_ord;
+
+        switch (dec_fields) {
+          case 0x00:
+            return new %(stl)s(machInst, rt, rn, true, 0);
+          case 0x02:
+            return new %(stlex)s(machInst, rt, rt2, rn, true, 0);
+          case 0x03:
             return new %(strex)s(machInst, rt, rt2, rn, true, 0);
-          case 0x19:
+          case 0x04:
+            return new %(lda)s(machInst, rt, rn, true, 0);
+          case 0x06:
+            return new %(ldaex)s(machInst, rt, rn, true, 0);
+          case 0x07:
             return new %(ldrex)s(machInst, rt, rn, true, 0);
-          case 0x1a:
+          case 0x0a:
+            return new %(stlexd)s(machInst, rt, rt2, rt2 + 1, rn, true, 0);
+          case 0x0b:
             return new %(strexd)s(machInst, rt, rt2, rt2 + 1, rn, true, 0);
-          case 0x1b:
+          case 0x0e:
+            return new %(ldaexd)s(machInst, rt, rt + 1, rn, true, 0);
+          case 0x0f:
             return new %(ldrexd)s(machInst, rt, rt + 1, rn, true, 0);
-          case 0x1c:
+          case 0x10:
+            return new %(stlb)s(machInst, rt, rn, true, 0);
+          case 0x12:
+            return new %(stlexb)s(machInst, rt, rt2, rn, true, 0);
+          case 0x13:
             return new %(strexb)s(machInst, rt, rt2, rn, true, 0);
-          case 0x1d:
+          case 0x14:
+            return new %(ldab)s(machInst, rt, rn, true, 0);
+          case 0x16:
+            return new %(ldaexb)s(machInst, rt, rn, true, 0);
+          case 0x17:
             return new %(ldrexb)s(machInst, rt, rn, true, 0);
-          case 0x1e:
+          case 0x18:
+            return new %(stlh)s(machInst, rt, rn, true, 0);
+          case 0x1a:
+            return new %(stlexh)s(machInst, rt, rt2, rn, true, 0);
+          case 0x1b:
             return new %(strexh)s(machInst, rt, rt2, rn, true, 0);
+          case 0x1c:
+            return new %(ldah)s(machInst, rt, rn, true, 0);
+          case 0x1e:
+            return new %(ldaexh)s(machInst, rt, rn, true, 0);
           case 0x1f:
             return new %(ldrexh)s(machInst, rt, rn, true, 0);
           default:
@@ -254,7 +287,23 @@
         "strex" : "STREX_" + storeImmClassName(False, True, False, size=4),
         "strexb" : "STREXB_" + storeImmClassName(False, True, False, size=1),
         "strexh" : "STREXH_" + storeImmClassName(False, True, False, size=2),
-        "strexd" : "STREXD_" + storeDoubleImmClassName(False, True, False)
+        "strexd" : "STREXD_" + storeDoubleImmClassName(False, True, False),
+
+        "lda" : "LDA_" + loadImmClassName(False, True, False, size=4),
+        "ldab" : "LDAB_" + loadImmClassName(False, True, False, size=1),
+        "ldah" : "LDAH_" + loadImmClassName(False, True, False, size=2),
+        "ldaex" : "LDAEX_" + loadImmClassName(False, True, False, size=4),
+        "ldaexb" : "LDAEXB_" + loadImmClassName(False, True, False, size=1),
+        "ldaexh" : "LDAEXH_" + loadImmClassName(False, True, False, size=2),
+        "ldaexd" : "LDAEXD_" + loadDoubleImmClassName(False, True, False),
+
+        "stl" : "STL_" + storeImmClassName(False, True, False, size=4),
+        "stlb" : "STLB_" + storeImmClassName(False, True, False, size=1),
+        "stlh" : "STLH_" + storeImmClassName(False, True, False, size=2),
+        "stlex" : "STLEX_" + storeImmClassName(False, True, False, size=4),
+        "stlexb" : "STLEXB_" + storeImmClassName(False, True, False, size=1),
+        "stlexh" : "STLEXH_" + storeImmClassName(False, True, False, size=2),
+        "stlexd" : "STLEXD_" + storeDoubleImmClassName(False, True, False)
     }
 }};
 
@@ -341,6 +390,21 @@
                       case 0x7:
                         return new %(strexd)s(machInst, rd, rt,
                                               rt2, rn, true, 0);
+                      case 0x8:
+                        return new %(stlb)s(machInst, rt, rn, true, 0);
+                      case 0x9:
+                        return new %(stlh)s(machInst, rt, rn, true, 0);
+                      case 0xa:
+                        return new %(stl)s(machInst, rt, rn, true, 0);
+                      case 0xc:
+                        return new %(stlexb)s(machInst, rd, rt, rn, true, 0);
+                      case 0xd:
+                        return new %(stlexh)s(machInst, rd, rt, rn, true, 0);
+                      case 0xe:
+                        return new %(stlex)s(machInst, rd, rt, rn, true, 0);
+                      case 0xf:
+                        return new %(stlexd)s(machInst, rd, rt,
+                                              rt2, rn, true, 0);
                       default:
                         return new Unknown(machInst);
                     }
@@ -356,6 +420,20 @@
                         return new %(ldrexh)s(machInst, rt, rn, true, 0);
                       case 0x7:
                         return new %(ldrexd)s(machInst, rt, rt2, rn, true, 0);
+                      case 0x8:
+                        return new %(ldab)s(machInst, rt, rn, true, 0);
+                      case 0x9:
+                        return new %(ldah)s(machInst, rt, rn, true, 0);
+                      case 0xa:
+                        return new %(lda)s(machInst, rt, rn, true, 0);
+                      case 0xc:
+                        return new %(ldaexb)s(machInst, rt, rn, true, 0);
+                      case 0xd:
+                        return new %(ldaexh)s(machInst, rt, rn, true, 0);
+                      case 0xe:
+                        return new %(ldaex)s(machInst, rt, rn, true, 0);
+                      case 0xf:
+                        return new %(ldaexd)s(machInst, rt, rt2, rn, true, 0);
                       default:
                         return new Unknown(machInst);
                     }
@@ -422,7 +500,22 @@
         "strd_p" : storeDoubleImmClassName(False, False, False),
         "strd_pw" : storeDoubleImmClassName(False, False, True),
         "strd_pu" : storeDoubleImmClassName(False, True, False),
-        "strd_puw" : storeDoubleImmClassName(False, True, True)
+        "strd_puw" : storeDoubleImmClassName(False, True, True),
+
+        "stl" : "STL_" + storeImmClassName(False, True, False, size=4),
+        "stlh" : "STLH_" + storeImmClassName(False, True, False, size=2),
+        "stlb" : "STLB_" + storeImmClassName(False, True, False, size=1),
+        "stlex" : "STLEX_" + storeImmClassName(False, True, False, size=4),
+        "stlexh" : "STLEXH_" + storeImmClassName(False, True, False, size=2),
+        "stlexb" : "STLEXB_" + storeImmClassName(False, True, False, size=1),
+        "stlexd" : "STLEXD_" + storeDoubleImmClassName(False, True, False),
+        "lda" : "LDA_" + loadImmClassName(False, True, False, size=4),
+        "ldah" : "LDAH_" + loadImmClassName(False, True, False, size=2),
+        "ldab" : "LDAB_" + loadImmClassName(False, True, False, size=1),
+        "ldaex" : "LDAEX_" + loadImmClassName(False, True, False, size=4),
+        "ldaexh" : "LDAEXH_" + loadImmClassName(False, True, False, size=2),
+        "ldaexb" : "LDAEXB_" + loadImmClassName(False, True, False, size=1),
+        "ldaexd" : "LDAEXD_" + loadDoubleImmClassName(False, True, False)
     }
 }};
 
diff --git a/src/arch/arm/isa/insts/ldr.isa b/src/arch/arm/isa/insts/ldr.isa
index 3edeb38..6e5122c 100644
--- a/src/arch/arm/isa/insts/ldr.isa
+++ b/src/arch/arm/isa/insts/ldr.isa
@@ -1,6 +1,6 @@
 // -*- mode:c++ -*-
 
-// Copyright (c) 2010-2011 ARM Limited
+// Copyright (c) 2010-2011,2019 ARM Limited
 // All rights reserved
 //
 // The license below extends only to copyright in the software and shall
@@ -173,11 +173,17 @@
             elif self.flavor == "iprefetch":
                 self.memFlags.append("Request::PREFETCH")
                 self.instFlags = ['IsInstPrefetch']
-            elif self.flavor == "exclusive":
-                self.memFlags.append("Request::LLSC")
             elif self.flavor == "normal":
                 self.memFlags.append("ArmISA::TLB::AllowUnaligned")
 
+            if self.flavor in ("exclusive", "acex"):
+                self.memFlags.append("Request::LLSC")
+
+            if self.flavor in ("acquire", "acex"):
+                self.instFlags.extend(["IsMemBarrier",
+                                       "IsWriteBarrier",
+                                       "IsReadBarrier"])
+
             # Disambiguate the class name for different flavors of loads
             if self.flavor != "normal":
                 self.Name = "%s_%s" % (self.name.upper(), self.Name)
@@ -235,8 +241,9 @@
             # Build the default class name
             self.Name = self.nameFunc(self.post, self.add, self.writeback)
 
+            self.instFlags = []
             # Add memory request flags where necessary
-            if self.flavor == "exclusive":
+            if self.flavor in ("exclusive", "acex"):
                 self.memFlags.append("Request::LLSC")
                 self.memFlags.append("ArmISA::TLB::AlignDoubleWord")
             else:
@@ -246,6 +253,11 @@
             if self.flavor != "normal":
                 self.Name = "%s_%s" % (self.name.upper(), self.Name)
 
+            if self.flavor in ("acquire", "acex"):
+                self.instFlags.extend(["IsMemBarrier",
+                                       "IsWriteBarrier",
+                                       "IsReadBarrier"])
+
         def emit(self):
             # Address computation code
             eaCode = "EA = Base"
@@ -279,7 +291,7 @@
             wbDecl = None
             if self.writeback:
                 wbDecl = self.wbDecl
-            self.emitHelper(base, wbDecl)
+            self.emitHelper(base, wbDecl, self.instFlags)
 
     def loadDoubleImmClassName(post, add, writeback):
         return memClassName("LOAD_IMMD", post, add, writeback, 4, False, False)
@@ -365,6 +377,14 @@
     LoadImm("ldrexb", False, True, False, size=1, flavor="exclusive").emit()
     LoadDoubleImm("ldrexd", False, True, False, flavor="exclusive").emit()
 
+    LoadImm("lda", False, True, False, size=4, flavor="acquire").emit()
+    LoadImm("ldah", False, True, False, size=2, flavor="acquire").emit()
+    LoadImm("ldab", False, True, False, size=1, flavor="acquire").emit()
+    LoadImm("ldaex", False, True, False, size=4, flavor="acex").emit()
+    LoadImm("ldaexh", False, True, False, size=2, flavor="acex").emit()
+    LoadImm("ldaexb", False, True, False, size=1, flavor="acex").emit()
+    LoadDoubleImm("ldaexd", False, True, False, flavor="acex").emit()
+
     LoadImm("vldr", False, True, False, size=4, flavor="fp").emit()
     LoadImm("vldr", False, False, False, size=4, flavor="fp").emit()
     LoadDoubleImm("vldr", False, True, False, flavor="fp").emit()
diff --git a/src/arch/arm/isa/insts/str.isa b/src/arch/arm/isa/insts/str.isa
index ea412aa..6b2e8cc 100644
--- a/src/arch/arm/isa/insts/str.isa
+++ b/src/arch/arm/isa/insts/str.isa
@@ -1,6 +1,6 @@
 // -*- mode:c++ -*-
 
-// Copyright (c) 2010-2011,2017 ARM Limited
+// Copyright (c) 2010-2011,2017,2019 ARM Limited
 // All rights reserved
 //
 // The license below extends only to copyright in the software and shall
@@ -183,12 +183,17 @@
             if self.user:
                 self.memFlags.append("ArmISA::TLB::UserMode")
 
-            if self.flavor == "exclusive":
+            if self.flavor in ("exclusive", "relex"):
                 self.instFlags.append("IsStoreConditional")
                 self.memFlags.append("Request::LLSC")
             elif self.flavor != "fp":
                 self.memFlags.append("ArmISA::TLB::AllowUnaligned")
 
+            if self.flavor in ("release", "relex"):
+                self.instFlags.extend(["IsMemBarrier",
+                                       "IsWriteBarrier",
+                                       "IsReadBarrier"])
+
             # Disambiguate the class name for different flavors of stores
             if self.flavor != "normal":
                 self.Name = "%s_%s" % (self.name.upper(), self.Name)
@@ -258,13 +263,18 @@
             self.Name = self.nameFunc(self.post, self.add, self.writeback)
 
             # Add memory request flags where necessary
-            if self.flavor == "exclusive":
+            if self.flavor in ("exclusive", "relex"):
                 self.instFlags.append("IsStoreConditional")
                 self.memFlags.append("Request::LLSC")
                 self.memFlags.append("ArmISA::TLB::AlignDoubleWord")
             else:
                 self.memFlags.append("ArmISA::TLB::AlignWord")
 
+            if self.flavor in ("release", "relex"):
+                self.instFlags.extend(["IsMemBarrier",
+                                       "IsWriteBarrier",
+                                       "IsReadBarrier"])
+
             # Disambiguate the class name for different flavors of stores
             if self.flavor != "normal":
                 self.Name = "%s_%s" % (self.name.upper(), self.Name)
@@ -389,6 +399,14 @@
     StoreDoubleImmEx("strexd", False, True, False,
                      flavor="exclusive").emit()
 
+    StoreImm("stl", False, True, False, size=4, flavor="release").emit()
+    StoreImm("stlh", False, True, False, size=2, flavor="release").emit()
+    StoreImm("stlb", False, True, False, size=1, flavor="release").emit()
+    StoreImmEx("stlex", False, True, False, size=4, flavor="relex").emit()
+    StoreImmEx("stlexh", False, True, False, size=2, flavor="relex").emit()
+    StoreImmEx("stlexb", False, True, False, size=1, flavor="relex").emit()
+    StoreDoubleImmEx("stlexd", False, True, False, flavor="relex").emit()
+
     StoreImm("vstr", False, True, False, size=4, flavor="fp").emit()
     StoreImm("vstr", False, False, False, size=4, flavor="fp").emit()
     StoreDoubleImm("vstr", False, True, False, flavor="fp").emit()