From 033b46253e6c7de33c5f8b51adb9d96ca606669d Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Wed, 21 Nov 2018 14:32:21 -0500
Subject: [PATCH] macro_interpreter: Implement AddWithCarry and
 SubtractWithBorrow.

- Used by Undertale.
---
 src/video_core/macro_interpreter.cpp | 29 +++++++++++++++++++++-------
 src/video_core/macro_interpreter.h   |  4 +++-
 2 files changed, 25 insertions(+), 8 deletions(-)

diff --git a/src/video_core/macro_interpreter.cpp b/src/video_core/macro_interpreter.cpp
index 335a8d4079..2b0dea5cd2 100644
--- a/src/video_core/macro_interpreter.cpp
+++ b/src/video_core/macro_interpreter.cpp
@@ -35,6 +35,7 @@ void MacroInterpreter::Reset() {
     // The next parameter index starts at 1, because $r1 already has the value of the first
     // parameter.
     next_parameter_index = 1;
+    carry_flag = false;
 }
 
 bool MacroInterpreter::Step(u32 offset, bool is_delay_slot) {
@@ -135,14 +136,28 @@ MacroInterpreter::Opcode MacroInterpreter::GetOpcode(u32 offset) const {
     return {macro_memory[offset + pc / sizeof(u32)]};
 }
 
-u32 MacroInterpreter::GetALUResult(ALUOperation operation, u32 src_a, u32 src_b) const {
+u32 MacroInterpreter::GetALUResult(ALUOperation operation, u32 src_a, u32 src_b) {
     switch (operation) {
-    case ALUOperation::Add:
-        return src_a + src_b;
-    // TODO(Subv): Implement AddWithCarry
-    case ALUOperation::Subtract:
-        return src_a - src_b;
-    // TODO(Subv): Implement SubtractWithBorrow
+    case ALUOperation::Add: {
+        const u64 result{static_cast<u64>(src_a) + src_b};
+        carry_flag = result > 0xffffffff;
+        return static_cast<u32>(result);
+    }
+    case ALUOperation::AddWithCarry: {
+        const u64 result{static_cast<u64>(src_a) + src_b + (carry_flag ? 1ULL : 0ULL)};
+        carry_flag = result > 0xffffffff;
+        return static_cast<u32>(result);
+    }
+    case ALUOperation::Subtract: {
+        const u64 result{static_cast<u64>(src_a) - src_b};
+        carry_flag = result < 0x100000000;
+        return static_cast<u32>(result);
+    }
+    case ALUOperation::SubtractWithBorrow: {
+        const u64 result{static_cast<u64>(src_a) - src_b - (carry_flag ? 0ULL : 1ULL)};
+        carry_flag = result < 0x100000000;
+        return static_cast<u32>(result);
+    }
     case ALUOperation::Xor:
         return src_a ^ src_b;
     case ALUOperation::Or:
diff --git a/src/video_core/macro_interpreter.h b/src/video_core/macro_interpreter.h
index 62d1ce289b..cde3602889 100644
--- a/src/video_core/macro_interpreter.h
+++ b/src/video_core/macro_interpreter.h
@@ -117,7 +117,7 @@ private:
     bool Step(u32 offset, bool is_delay_slot);
 
     /// Calculates the result of an ALU operation. src_a OP src_b;
-    u32 GetALUResult(ALUOperation operation, u32 src_a, u32 src_b) const;
+    u32 GetALUResult(ALUOperation operation, u32 src_a, u32 src_b);
 
     /// Performs the result operation on the input result and stores it in the specified register
     /// (if necessary).
@@ -165,5 +165,7 @@ private:
     std::vector<u32> parameters;
     /// Index of the next parameter that will be fetched by the 'parm' instruction.
     u32 next_parameter_index = 0;
+
+    bool carry_flag{};
 };
 } // namespace Tegra