From f0525a1eb4bc133f43c6dd10166965467a34dd45 Mon Sep 17 00:00:00 2001
From: bunnei <ericbunnie@gmail.com>
Date: Sun, 27 Apr 2014 12:39:57 -0400
Subject: [PATCH] added code to LCD modules keep track of framebuffer location
 in FCRAM or VRAM

---
 src/core/hw/lcd.cpp | 91 ++++++++++++++++++++++++++++++++++++++++++++-
 src/core/hw/lcd.h   | 77 +++++++++++++++++++++++++++++++-------
 2 files changed, 153 insertions(+), 15 deletions(-)

diff --git a/src/core/hw/lcd.cpp b/src/core/hw/lcd.cpp
index 822cd16473..6468053f27 100644
--- a/src/core/hw/lcd.cpp
+++ b/src/core/hw/lcd.cpp
@@ -6,19 +6,107 @@
 #include "common/log.h"
 
 #include "core/core.h"
+#include "core/mem_map.h"
 #include "core/hw/lcd.h"
 
 #include "video_core/video_core.h"
 
 namespace LCD {
 
+Registers g_regs;
+
 static const u32 kFrameTicks = 268123480 / 60;  ///< 268MHz / 60 frames per second
 
 u64 g_last_ticks = 0; ///< Last CPU ticks
 
+/**
+ * Sets whether the framebuffers are in the GSP heap (FCRAM) or VRAM
+ * @param 
+ */
+void SetFramebufferLocation(const FramebufferLocation mode) {
+    switch (mode) {
+    case FRAMEBUFFER_LOCATION_FCRAM:
+        g_regs.framebuffer_top_left_1   = PADDR_TOP_LEFT_FRAME1;
+        g_regs.framebuffer_top_left_2   = PADDR_TOP_LEFT_FRAME2;
+        g_regs.framebuffer_top_right_1  = PADDR_TOP_RIGHT_FRAME1;
+        g_regs.framebuffer_top_right_2  = PADDR_TOP_RIGHT_FRAME2;
+        g_regs.framebuffer_sub_left_1   = PADDR_SUB_FRAME1;
+        //g_regs.framebuffer_sub_left_2  = unknown;
+        g_regs.framebuffer_sub_right_1  = PADDR_SUB_FRAME2;
+        //g_regs.framebufferr_sub_right_2 = unknown;
+        break;
+
+    case FRAMEBUFFER_LOCATION_VRAM:
+        g_regs.framebuffer_top_left_1   = PADDR_VRAM_TOP_LEFT_FRAME1;
+        g_regs.framebuffer_top_left_2   = PADDR_VRAM_TOP_LEFT_FRAME2;
+        g_regs.framebuffer_top_right_1  = PADDR_VRAM_TOP_RIGHT_FRAME1;
+        g_regs.framebuffer_top_right_2  = PADDR_VRAM_TOP_RIGHT_FRAME2;
+        g_regs.framebuffer_sub_left_1   = PADDR_VRAM_SUB_FRAME1;
+        //g_regs.framebuffer_sub_left_2  = unknown;
+        g_regs.framebuffer_sub_right_1  = PADDR_VRAM_SUB_FRAME2;
+        //g_regs.framebufferr_sub_right_2 = unknown;
+        break;
+    }
+}
+
+/**
+ * Gets the location of the framebuffers
+ * @return Location of framebuffers as FramebufferLocation enum
+ */
+const FramebufferLocation GetFramebufferLocation() {
+    if ((g_regs.framebuffer_top_right_1 & ~Memory::VRAM_MASK) == Memory::VRAM_PADDR) {
+        return FRAMEBUFFER_LOCATION_VRAM;
+    } else if ((g_regs.framebuffer_top_right_1 & ~Memory::FCRAM_MASK) == Memory::FCRAM_PADDR) {
+        return FRAMEBUFFER_LOCATION_FCRAM;
+    } else {
+        ERROR_LOG(LCD, "unknown framebuffer location!");
+    }
+    return FRAMEBUFFER_LOCATION_UNKNOWN;
+}
+
+/**
+ * Gets a read-only pointer to a framebuffer in memory
+ * @param address Physical address of framebuffer
+ * @return Returns const pointer to raw framebuffer
+ */
+const u8* GetFramebufferPointer(const u32 address) {
+    switch (GetFramebufferLocation()) {
+    case FRAMEBUFFER_LOCATION_FCRAM:
+        return (const u8*)Memory::GetPointer(Memory::VirtualAddressFromPhysical_FCRAM(address));
+    case FRAMEBUFFER_LOCATION_VRAM:
+        return (const u8*)Memory::GetPointer(Memory::VirtualAddressFromPhysical_VRAM(address));
+    default:
+        ERROR_LOG(LCD, "unknown framebuffer location");
+    }
+    return NULL;
+}
+
 template <typename T>
 inline void Read(T &var, const u32 addr) {
-    ERROR_LOG(LCD, "unknown Read%d @ 0x%08X", sizeof(var) * 8, addr);
+    switch (addr) {
+    case REG_FRAMEBUFFER_TOP_LEFT_1:
+        var = g_regs.framebuffer_top_left_1;
+        break;
+    case REG_FRAMEBUFFER_TOP_LEFT_2:
+        var = g_regs.framebuffer_top_left_2;
+        break;
+    case REG_FRAMEBUFFER_TOP_RIGHT_1:
+        var = g_regs.framebuffer_top_right_1;
+        break;
+    case REG_FRAMEBUFFER_TOP_RIGHT_2:
+        var = g_regs.framebuffer_top_right_2;
+        break;
+    case REG_FRAMEBUFFER_SUB_LEFT_1:
+        var = g_regs.framebuffer_sub_left_1;
+        break;
+    case REG_FRAMEBUFFER_SUB_RIGHT_1:
+        var = g_regs.framebuffer_sub_right_1;
+        break;
+    default:
+        ERROR_LOG(LCD, "unknown Read%d @ 0x%08X", sizeof(var) * 8, addr);
+        break;
+    }
+    
 }
 
 template <typename T>
@@ -51,6 +139,7 @@ void Update() {
 /// Initialize hardware
 void Init() {
     g_last_ticks = Core::g_app_core->GetTicks();
+    SetFramebufferLocation(FRAMEBUFFER_LOCATION_FCRAM);
     NOTICE_LOG(LCD, "initialized OK");
 }
 
diff --git a/src/core/hw/lcd.h b/src/core/hw/lcd.h
index b047e7ceae..2dd3b4adc3 100644
--- a/src/core/hw/lcd.h
+++ b/src/core/hw/lcd.h
@@ -8,6 +8,19 @@
 
 namespace LCD {
 
+struct Registers {
+    u32 framebuffer_top_left_1;
+    u32 framebuffer_top_left_2;
+    u32 framebuffer_top_right_1;
+    u32 framebuffer_top_right_2;
+    u32 framebuffer_sub_left_1;
+    u32 framebuffer_sub_left_2;
+    u32 framebuffer_sub_right_1;
+    u32 framebuffer_sub_right_2;
+};
+
+extern Registers g_regs;
+
 enum {
     TOP_ASPECT_X        = 0x5,
     TOP_ASPECT_Y        = 0x3,
@@ -17,24 +30,60 @@ enum {
     BOTTOM_WIDTH        = 320,
 
     // Physical addresses in FCRAM used by ARM9 applications - these are correct for real hardware 
-    FRAMEBUFFER_SEL     = 0x20184E59,
-    TOP_LEFT_FRAME1     = 0x20184E60,
-    TOP_LEFT_FRAME2     = 0x201CB370,
-    TOP_RIGHT_FRAME1    = 0x20282160,
-    TOP_RIGHT_FRAME2    = 0x202C8670,
-    SUB_FRAME1          = 0x202118E0,
-    SUB_FRAME2          = 0x20249CF0,
+    PADDR_FRAMEBUFFER_SEL       = 0x20184E59,
+    PADDR_TOP_LEFT_FRAME1       = 0x20184E60,
+    PADDR_TOP_LEFT_FRAME2       = 0x201CB370,
+    PADDR_TOP_RIGHT_FRAME1      = 0x20282160,
+    PADDR_TOP_RIGHT_FRAME2      = 0x202C8670,
+    PADDR_SUB_FRAME1            = 0x202118E0,
+    PADDR_SUB_FRAME2            = 0x20249CF0,
 
     // Physical addresses in VRAM - I'm not sure how these are actually allocated (so not real)
-    VRAM_FRAMEBUFFER_SEL    = 0x18184E59,
-    VRAM_TOP_LEFT_FRAME1    = 0x18184E60,
-    VRAM_TOP_LEFT_FRAME2    = 0x181CB370,
-    VRAM_TOP_RIGHT_FRAME1   = 0x18282160,
-    VRAM_TOP_RIGHT_FRAME2   = 0x182C8670,
-    VRAM_SUB_FRAME1         = 0x182118E0,
-    VRAM_SUB_FRAME2         = 0x18249CF0,
+    PADDR_VRAM_FRAMEBUFFER_SEL  = 0x18184E59,
+    PADDR_VRAM_TOP_LEFT_FRAME1  = 0x18184E60,
+    PADDR_VRAM_TOP_LEFT_FRAME2  = 0x181CB370,
+    PADDR_VRAM_TOP_RIGHT_FRAME1 = 0x18282160,
+    PADDR_VRAM_TOP_RIGHT_FRAME2 = 0x182C8670,
+    PADDR_VRAM_SUB_FRAME1       = 0x182118E0,
+    PADDR_VRAM_SUB_FRAME2       = 0x18249CF0,
 };
 
+enum {
+    REG_FRAMEBUFFER_TOP_LEFT_1  = 0x1EF00468,   // Main LCD, first framebuffer for 3D left
+    REG_FRAMEBUFFER_TOP_LEFT_2  = 0x1EF0046C,   // Main LCD, second framebuffer for 3D left
+    REG_FRAMEBUFFER_TOP_RIGHT_1 = 0x1EF00494,   // Main LCD, first framebuffer for 3D right
+    REG_FRAMEBUFFER_TOP_RIGHT_2 = 0x1EF00498,   // Main LCD, second framebuffer for 3D right
+    REG_FRAMEBUFFER_SUB_LEFT_1  = 0x1EF00568,   // Sub LCD, first framebuffer
+    REG_FRAMEBUFFER_SUB_LEFT_2  = 0x1EF0056C,   // Sub LCD, second framebuffer
+    REG_FRAMEBUFFER_SUB_RIGHT_1 = 0x1EF00594,   // Sub LCD, unused first framebuffer
+    REG_FRAMEBUFFER_SUB_RIGHT_2 = 0x1EF00598,   // Sub LCD, unused second framebuffer
+};
+
+/// Framebuffer location
+enum FramebufferLocation {
+    FRAMEBUFFER_LOCATION_UNKNOWN,   ///< Framebuffer location is unknown
+    FRAMEBUFFER_LOCATION_FCRAM,  ///< Framebuffer is in the GSP heap
+    FRAMEBUFFER_LOCATION_VRAM,      ///< Framebuffer is in VRAM
+};
+
+/**
+ * Sets whether the framebuffers are in the GSP heap (FCRAM) or VRAM
+ * @param 
+ */
+void SetFramebufferLocation(const FramebufferLocation mode);
+
+/**
+ * Gets a read-only pointer to a framebuffer in memory
+ * @param address Physical address of framebuffer
+ * @return Returns const pointer to raw framebuffer
+ */
+const u8* GetFramebufferPointer(const u32 address);
+
+/**
+ * Gets the location of the framebuffers
+ */
+const FramebufferLocation GetFramebufferLocation();
+
 template <typename T>
 inline void Read(T &var, const u32 addr);