AMOs should always return store faults, not load faults
authorAndrew Waterman <andrew@sifive.com>
Thu, 10 Nov 2016 21:40:37 +0000 (13:40 -0800)
committerAndrew Waterman <andrew@sifive.com>
Thu, 10 Nov 2016 21:40:37 +0000 (13:40 -0800)
This commit also factors out the common AMO code into mmu_t.

19 files changed:
riscv/insns/amoadd_d.h
riscv/insns/amoadd_w.h
riscv/insns/amoand_d.h
riscv/insns/amoand_w.h
riscv/insns/amomax_d.h
riscv/insns/amomax_w.h
riscv/insns/amomaxu_d.h
riscv/insns/amomaxu_w.h
riscv/insns/amomin_d.h
riscv/insns/amomin_w.h
riscv/insns/amominu_d.h
riscv/insns/amominu_w.h
riscv/insns/amoor_d.h
riscv/insns/amoor_w.h
riscv/insns/amoswap_d.h
riscv/insns/amoswap_w.h
riscv/insns/amoxor_d.h
riscv/insns/amoxor_w.h
riscv/mmu.h

index 9c7c124d7c37cbbc5e09ee945c5f3af8d64a2f53..6090fbc530d078cee63ea31bb78ecf70a1c6a534 100644 (file)
@@ -1,5 +1,3 @@
 require_extension('A');
 require_rv64;
-reg_t v = MMU.load_uint64(RS1);
-MMU.store_uint64(RS1, RS2 + v);
-WRITE_RD(v);
+WRITE_RD(MMU.amo_uint64(RS1, [&](uint64_t lhs) { return lhs + RS2; }));
index 7ac59b02442544e96ea1c761011d020037d2b732..2c6471afbe6e2dcb40fa504c7b4fc77739e72d9f 100644 (file)
@@ -1,4 +1,2 @@
 require_extension('A');
-reg_t v = MMU.load_int32(RS1);
-MMU.store_uint32(RS1, RS2 + v);
-WRITE_RD(v);
+WRITE_RD(sext32(MMU.amo_uint32(RS1, [&](uint32_t lhs) { return lhs + RS2; })));
index 7aa6386887002fab5e9cb32aadd38e13179f605b..80aea184de5521c64248ded6ff0c2ea79078c6a0 100644 (file)
@@ -1,5 +1,3 @@
 require_extension('A');
 require_rv64;
-reg_t v = MMU.load_uint64(RS1);
-MMU.store_uint64(RS1, RS2 & v);
-WRITE_RD(v);
+WRITE_RD(MMU.amo_uint64(RS1, [&](uint64_t lhs) { return lhs & RS2; }));
index 7db2160a4538a11b425c33441ea1a43254ecdd81..f7e1ba7c06262b785db4d20ae7a32ab2220f3bb6 100644 (file)
@@ -1,4 +1,2 @@
 require_extension('A');
-reg_t v = MMU.load_int32(RS1);
-MMU.store_uint32(RS1, RS2 & v);
-WRITE_RD(v);
+WRITE_RD(sext32(MMU.amo_uint32(RS1, [&](uint32_t lhs) { return lhs & RS2; })));
index 0f6da187bc347dacc5972b78e7a52011e4934a99..496d8ada9be068e850fc9b0944cbc6e338e8c893 100644 (file)
@@ -1,5 +1,3 @@
 require_extension('A');
 require_rv64;
-sreg_t v = MMU.load_int64(RS1);
-MMU.store_uint64(RS1, std::max(sreg_t(RS2),v));
-WRITE_RD(v);
+WRITE_RD(MMU.amo_uint64(RS1, [&](int64_t lhs) { return std::max(lhs, int64_t(RS2)); }));
index 8c9222bc1b71af3d32eab643496187e395677380..757bdd2ccb7bdab94d6a3fade459acf17f66bd2d 100644 (file)
@@ -1,4 +1,2 @@
 require_extension('A');
-int32_t v = MMU.load_int32(RS1);
-MMU.store_uint32(RS1, std::max(int32_t(RS2),v));
-WRITE_RD(v);
+WRITE_RD(sext32(MMU.amo_uint32(RS1, [&](int32_t lhs) { return std::max(lhs, int32_t(RS2)); })));
index 6760f9191072acc1bebfa1419ebc2646b315106d..12b173313d9e4f1636e13a67fea6785fbae8f8ae 100644 (file)
@@ -1,5 +1,3 @@
 require_extension('A');
 require_rv64;
-reg_t v = MMU.load_uint64(RS1);
-MMU.store_uint64(RS1, std::max(RS2,v));
-WRITE_RD(v);
+WRITE_RD(MMU.amo_uint64(RS1, [&](uint64_t lhs) { return std::max(lhs, RS2); }));
index fc83dc32858ad0923cb6b4f036d386321270b098..538df1c40077dda756ae3b66813f92e5fde0a6d2 100644 (file)
@@ -1,4 +1,2 @@
 require_extension('A');
-uint32_t v = MMU.load_int32(RS1);
-MMU.store_uint32(RS1, std::max(uint32_t(RS2),v));
-WRITE_RD((int32_t)v);
+WRITE_RD(sext32(MMU.amo_uint32(RS1, [&](uint32_t lhs) { return std::max(lhs, uint32_t(RS2)); })));
index 8d0898461e9aa456498ad02615d1f655142851c4..725d9839f8f186aeaec31481cb15fa71fbe72f47 100644 (file)
@@ -1,5 +1,3 @@
 require_extension('A');
 require_rv64;
-sreg_t v = MMU.load_int64(RS1);
-MMU.store_uint64(RS1, std::min(sreg_t(RS2),v));
-WRITE_RD(v);
+WRITE_RD(MMU.amo_uint64(RS1, [&](int64_t lhs) { return std::min(lhs, int64_t(RS2)); }));
index 31a8df86dff8b11ce6c9f91c7a8873f1dcf93445..ee53faa0cd61cad91f5dfaa5d59faaf1cc368ea3 100644 (file)
@@ -1,4 +1,2 @@
 require_extension('A');
-int32_t v = MMU.load_int32(RS1);
-MMU.store_uint32(RS1, std::min(int32_t(RS2),v));
-WRITE_RD(v);
+WRITE_RD(sext32(MMU.amo_uint32(RS1, [&](int32_t lhs) { return std::min(lhs, int32_t(RS2)); })));
index 8a77edcfcde14805153aa54e217890504d5d9e27..15b6c0a48bad12e9cafd9738fe7481bc933eb974 100644 (file)
@@ -1,5 +1,3 @@
 require_extension('A');
 require_rv64;
-reg_t v = MMU.load_uint64(RS1);
-MMU.store_uint64(RS1, std::min(RS2,v));
-WRITE_RD(v);
+WRITE_RD(MMU.amo_uint64(RS1, [&](uint64_t lhs) { return std::min(lhs, RS2); }));
index 2b6aaa3bfc8f24d60a4778924ad0fa385b4e46a7..52e1141b87cd9cce8945e9394bc3bbce7b543d06 100644 (file)
@@ -1,4 +1,2 @@
 require_extension('A');
-uint32_t v = MMU.load_int32(RS1);
-MMU.store_uint32(RS1, std::min(uint32_t(RS2),v));
-WRITE_RD((int32_t)v);
+WRITE_RD(sext32(MMU.amo_uint32(RS1, [&](uint32_t lhs) { return std::min(lhs, uint32_t(RS2)); })));
index 5a697172408995031dccafcb8065bf0be1b2306a..de8762745b3768a66be72da7c2bbcfc9d6d32b3f 100644 (file)
@@ -1,5 +1,3 @@
 require_extension('A');
 require_rv64;
-reg_t v = MMU.load_uint64(RS1);
-MMU.store_uint64(RS1, RS2 | v);
-WRITE_RD(v);
+WRITE_RD(MMU.amo_uint64(RS1, [&](uint64_t lhs) { return lhs | RS2; }));
index f5b96b96b2833981db0a0a8dfbe169f96f6a01ac..3455981d86944802bdea0afae5689e05b7c28de2 100644 (file)
@@ -1,4 +1,2 @@
 require_extension('A');
-reg_t v = MMU.load_int32(RS1);
-MMU.store_uint32(RS1, RS2 | v);
-WRITE_RD(v);
+WRITE_RD(sext32(MMU.amo_uint32(RS1, [&](uint32_t lhs) { return lhs | RS2; })));
index 8cf1411fe791b7e382c1f9ac173a4e85d9366f9b..e1bffdeb5cdda44cbc0e9b64f4602bec5eaf1632 100644 (file)
@@ -1,5 +1,3 @@
 require_extension('A');
 require_rv64;
-reg_t v = MMU.load_uint64(RS1);
-MMU.store_uint64(RS1, RS2);
-WRITE_RD(v);
+WRITE_RD(MMU.amo_uint64(RS1, [&](uint64_t lhs) { return RS2; }));
index 0764d59e598c423391a1c188056eeb0cef4477eb..0f78369c76eeccec56f4c7e3d48d3687245b2839 100644 (file)
@@ -1,4 +1,2 @@
 require_extension('A');
-reg_t v = MMU.load_int32(RS1);
-MMU.store_uint32(RS1, RS2);
-WRITE_RD(v);
+WRITE_RD(sext32(MMU.amo_uint32(RS1, [&](uint32_t lhs) { return RS2; })));
index 39708223e8bb1a1c790ca97a950f628cb218839f..1b3c0bf41fb9262a6fd2330772e54029770e3e04 100644 (file)
@@ -1,5 +1,3 @@
 require_extension('A');
 require_rv64;
-reg_t v = MMU.load_uint64(RS1);
-MMU.store_uint64(RS1, RS2 ^ v);
-WRITE_RD(v);
+WRITE_RD(MMU.amo_uint64(RS1, [&](uint64_t lhs) { return lhs ^ RS2; }));
index 9889b646e3e194540724579e1b3946514e55d115..a1ea82f1d83b9f71e882770915d8c253dbf16e33 100644 (file)
@@ -1,4 +1,2 @@
 require_extension('A');
-reg_t v = MMU.load_int32(RS1);
-MMU.store_uint32(RS1, RS2 ^ v);
-WRITE_RD(v);
+WRITE_RD(sext32(MMU.amo_uint32(RS1, [&](uint32_t lhs) { return lhs ^ RS2; })));
index 1f8d34b3a9ad2f0bfcc5793640c74524e04f532b..105908e5b7de4baf4056c46ad43d484442e254c5 100644 (file)
@@ -105,12 +105,32 @@ public:
         store_slow_path(addr, sizeof(type##_t), (const uint8_t*)&val); \
     }
 
+  // template for functions that perform an atomic memory operation
+  #define amo_func(type) \
+    template<typename op> \
+    type##_t amo_##type(reg_t addr, op f) { \
+      if (addr & (sizeof(type##_t)-1)) \
+        throw trap_store_address_misaligned(addr); \
+      try { \
+        auto lhs = load_##type(addr); \
+        store_##type(addr, f(lhs)); \
+        return lhs; \
+      } catch (trap_load_access_fault& t) { \
+        /* AMO faults should be reported as store faults */ \
+        throw trap_store_access_fault(t.get_badaddr()); \
+      } \
+    }
+
   // store value to memory at aligned address
   store_func(uint8)
   store_func(uint16)
   store_func(uint32)
   store_func(uint64)
 
+  // perform an atomic memory operation at an aligned address
+  amo_func(uint32)
+  amo_func(uint64)
+
   static const reg_t ICACHE_ENTRIES = 1024;
 
   inline size_t icache_index(reg_t addr)