From a507ea23c157abfc490cbb0c85154b23c4b079b9 Mon Sep 17 00:00:00 2001
From: Lioncash <mathew1800@gmail.com>
Date: Mon, 27 Jul 2015 21:40:48 -0400
Subject: [PATCH] dyncom: Migrate exclusive memory access control into armstate

---
 .../arm/dyncom/arm_dyncom_interpreter.cpp     | 60 ++++---------------
 src/core/arm/skyeye_common/armstate.h         | 25 +++++++-
 2 files changed, 35 insertions(+), 50 deletions(-)

diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
index e855a4487..69228180e 100644
--- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
+++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
@@ -47,27 +47,6 @@ enum {
 
 typedef unsigned int (*shtop_fp_t)(ARMul_State* cpu, unsigned int sht_oper);
 
-// Defines a reservation granule of 2 words, which protects the first 2 words starting at the tag.
-// This is the smallest granule allowed by the v7 spec, and is coincidentally just large enough to
-// support LDR/STREXD.
-static const u32 RESERVATION_GRANULE_MASK = 0xFFFFFFF8;
-
-// Exclusive memory access
-static int exclusive_detect(ARMul_State* state, u32 addr) {
-    if(state->exclusive_tag == (addr & RESERVATION_GRANULE_MASK))
-        return 0;
-    else
-        return -1;
-}
-
-static void add_exclusive_addr(ARMul_State* state, u32 addr){
-    state->exclusive_tag = addr & RESERVATION_GRANULE_MASK;
-}
-
-static void remove_exclusive(ARMul_State* state, u32 addr){
-    state->exclusive_tag = 0xFFFFFFFF;
-}
-
 static int CondPassed(ARMul_State* cpu, unsigned int cond) {
     const u32 NFLAG = cpu->NFlag;
     const u32 ZFLAG = cpu->ZFlag;
@@ -4170,9 +4149,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
 
     CLREX_INST:
     {
-        remove_exclusive(cpu, 0);
-        cpu->exclusive_state = 0;
-
+        cpu->UnsetExclusiveMemoryAddress();
         cpu->Reg[15] += cpu->GetInstructionSize();
         INC_PC(sizeof(clrex_inst));
         FETCH_INST;
@@ -4539,8 +4516,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
             generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
             unsigned int read_addr = RN;
 
-            add_exclusive_addr(cpu, read_addr);
-            cpu->exclusive_state = 1;
+            cpu->SetExclusiveMemoryAddress(read_addr);
 
             RD = cpu->ReadMemory32(read_addr);
             if (inst_cream->Rd == 15) {
@@ -4559,8 +4535,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
             generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
             unsigned int read_addr = RN;
 
-            add_exclusive_addr(cpu, read_addr);
-            cpu->exclusive_state = 1;
+            cpu->SetExclusiveMemoryAddress(read_addr);
 
             RD = Memory::Read8(read_addr);
             if (inst_cream->Rd == 15) {
@@ -4579,8 +4554,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
             generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
             unsigned int read_addr = RN;
 
-            add_exclusive_addr(cpu, read_addr);
-            cpu->exclusive_state = 1;
+            cpu->SetExclusiveMemoryAddress(read_addr);
 
             RD = cpu->ReadMemory16(read_addr);
             if (inst_cream->Rd == 15) {
@@ -4599,8 +4573,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
             generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
             unsigned int read_addr = RN;
 
-            add_exclusive_addr(cpu, read_addr);
-            cpu->exclusive_state = 1;
+            cpu->SetExclusiveMemoryAddress(read_addr);
 
             RD  = cpu->ReadMemory32(read_addr);
             RD2 = cpu->ReadMemory32(read_addr + 4);
@@ -6085,10 +6058,8 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
             generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
             unsigned int write_addr = cpu->Reg[inst_cream->Rn];
 
-            if ((exclusive_detect(cpu, write_addr) == 0) && (cpu->exclusive_state == 1)) {
-                remove_exclusive(cpu, write_addr);
-                cpu->exclusive_state = 0;
-
+            if (cpu->IsExclusiveMemoryAccess(write_addr)) {
+                cpu->UnsetExclusiveMemoryAddress();
                 cpu->WriteMemory32(write_addr, RM);
                 RD = 0;
             } else {
@@ -6107,10 +6078,8 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
             generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
             unsigned int write_addr = cpu->Reg[inst_cream->Rn];
 
-            if ((exclusive_detect(cpu, write_addr) == 0) && (cpu->exclusive_state == 1)) {
-                remove_exclusive(cpu, write_addr);
-                cpu->exclusive_state = 0;
-
+            if (cpu->IsExclusiveMemoryAccess(write_addr)) {
+                cpu->UnsetExclusiveMemoryAddress();
                 Memory::Write8(write_addr, cpu->Reg[inst_cream->Rm]);
                 RD = 0;
             } else {
@@ -6129,9 +6098,8 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
             generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
             unsigned int write_addr = cpu->Reg[inst_cream->Rn];
 
-            if ((exclusive_detect(cpu, write_addr) == 0) && (cpu->exclusive_state == 1)) {
-                remove_exclusive(cpu, write_addr);
-                cpu->exclusive_state = 0;
+            if (cpu->IsExclusiveMemoryAccess(write_addr)) {
+                cpu->UnsetExclusiveMemoryAddress();
 
                 const u32 rt  = cpu->Reg[inst_cream->Rm + 0];
                 const u32 rt2 = cpu->Reg[inst_cream->Rm + 1];
@@ -6161,10 +6129,8 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
             generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
             unsigned int write_addr = cpu->Reg[inst_cream->Rn];
 
-            if ((exclusive_detect(cpu, write_addr) == 0) && (cpu->exclusive_state == 1)) {
-                remove_exclusive(cpu, write_addr);
-                cpu->exclusive_state = 0;
-
+            if (cpu->IsExclusiveMemoryAccess(write_addr)) {
+                cpu->UnsetExclusiveMemoryAddress();
                 cpu->WriteMemory16(write_addr, RM);
                 RD = 0;
             } else {
diff --git a/src/core/arm/skyeye_common/armstate.h b/src/core/arm/skyeye_common/armstate.h
index 88c1dab9d..b364e2621 100644
--- a/src/core/arm/skyeye_common/armstate.h
+++ b/src/core/arm/skyeye_common/armstate.h
@@ -163,6 +163,19 @@ public:
     u32 ReadCP15Register(u32 crn, u32 opcode_1, u32 crm, u32 opcode_2) const;
     void WriteCP15Register(u32 value, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2);
 
+    // Exclusive memory access functions
+    bool IsExclusiveMemoryAccess(u32 address) const {
+        return exclusive_state && exclusive_tag == (address & RESERVATION_GRANULE_MASK);
+    }
+    void SetExclusiveMemoryAddress(u32 address) {
+        exclusive_tag = address & RESERVATION_GRANULE_MASK;
+        exclusive_state = true;
+    }
+    void UnsetExclusiveMemoryAddress() {
+        exclusive_tag = 0xFFFFFFFF;
+        exclusive_state = false;
+    }
+
     // Whether or not the given CPU is in big endian mode (E bit is set)
     bool InBigEndianMode() const {
         return (Cpsr & (1 << 9)) != 0;
@@ -203,9 +216,6 @@ public:
 
     u32 Mode;          // The current mode
     u32 Bank;          // The current register bank
-    u32 exclusive_tag; // The address for which the local monitor is in exclusive access mode
-    u32 exclusive_state;
-    u32 exclusive_result;
 
     u32 NFlag, ZFlag, CFlag, VFlag, IFFlags; // Dummy flags for speed
     unsigned int shifter_carry_out;
@@ -230,4 +240,13 @@ public:
 
 private:
     void ResetMPCoreCP15Registers();
+
+    // Defines a reservation granule of 2 words, which protects the first 2 words starting at the tag.
+    // This is the smallest granule allowed by the v7 spec, and is coincidentally just large enough to
+    // support LDR/STREXD.
+    static const u32 RESERVATION_GRANULE_MASK = 0xFFFFFFF8;
+
+    u32 exclusive_tag; // The address for which the local monitor is in exclusive access mode
+    u32 exclusive_result;
+    bool exclusive_state;
 };