diff options
Diffstat (limited to 'src/core/hw/gpu.h')
-rw-r--r-- | src/core/hw/gpu.h | 219 |
1 files changed, 179 insertions, 40 deletions
diff --git a/src/core/hw/gpu.h b/src/core/hw/gpu.h index 3314ba989..42f18a0e7 100644 --- a/src/core/hw/gpu.h +++ b/src/core/hw/gpu.h @@ -5,43 +5,168 @@ #pragma once #include "common/common_types.h" +#include "common/bit_field.h" +#include "common/register_set.h" namespace GPU { static const u32 kFrameCycles = 268123480 / 60; ///< 268MHz / 60 frames per second static const u32 kFrameTicks = kFrameCycles / 3; ///< Approximate number of instructions/frame -struct Registers { +// MMIO region 0x1EFxxxxx +struct Regs { enum Id : u32 { - FramebufferTopLeft1 = 0x1EF00468, // Main LCD, first framebuffer for 3D left - FramebufferTopLeft2 = 0x1EF0046C, // Main LCD, second framebuffer for 3D left - FramebufferTopRight1 = 0x1EF00494, // Main LCD, first framebuffer for 3D right - FramebufferTopRight2 = 0x1EF00498, // Main LCD, second framebuffer for 3D right - FramebufferSubLeft1 = 0x1EF00568, // Sub LCD, first framebuffer - FramebufferSubLeft2 = 0x1EF0056C, // Sub LCD, second framebuffer - FramebufferSubRight1 = 0x1EF00594, // Sub LCD, unused first framebuffer - FramebufferSubRight2 = 0x1EF00598, // Sub LCD, unused second framebuffer - - CommandListSize = 0x1EF018E0, - CommandListAddress = 0x1EF018E8, - ProcessCommandList = 0x1EF018F0, + MemoryFill = 0x00004, // + 5,6,7; second block at 8-11 + + FramebufferTop = 0x00117, // + 11a,11b,11c,11d(?),11e...126 + FramebufferBottom = 0x00157, // + 15a,15b,15c,15d(?),15e...166 + + DisplayTransfer = 0x00300, // + 301,302,303,304,305,306 + + CommandProcessor = 0x00638, // + 63a,63c + + NumIds = 0x01000 + }; + + template<Id id> + struct Struct; + + enum class FramebufferFormat : u32 { + RGBA8 = 0, + RGB8 = 1, + RGB565 = 2, + RGB5A1 = 3, + RGBA4 = 4, + }; +}; + +template<> +struct Regs::Struct<Regs::MemoryFill> { + u32 address_start; + u32 address_end; // ? + u32 size; + u32 value; // ? + + inline u32 GetStartAddress() const { + return address_start * 8; + } + + inline u32 GetEndAddress() const { + return address_end * 8; + } +}; +static_assert(sizeof(Regs::Struct<Regs::MemoryFill>) == 0x10, "Structure size and register block length don't match"); + +template<> +struct Regs::Struct<Regs::FramebufferTop> { + using Format = Regs::FramebufferFormat; + + union { + u32 size; + + BitField< 0, 16, u32> width; + BitField<16, 16, u32> height; + }; + + u32 pad0[2]; + + u32 address_left1; + u32 address_left2; + + union { + u32 format; + + BitField< 0, 3, Format> color_format; + }; + + u32 pad1; + + union { + u32 active_fb; + + // 0: Use parameters ending with "1" + // 1: Use parameters ending with "2" + BitField<0, 1, u32> second_fb_active; + }; + + u32 pad2[5]; + + // Distance between two pixel rows, in bytes + u32 stride; + + u32 address_right1; + u32 address_right2; +}; + +template<> +struct Regs::Struct<Regs::FramebufferBottom> : public Regs::Struct<Regs::FramebufferTop> { +}; +static_assert(sizeof(Regs::Struct<Regs::FramebufferTop>) == 0x40, "Structure size and register block length don't match"); + +template<> +struct Regs::Struct<Regs::DisplayTransfer> { + using Format = Regs::FramebufferFormat; + + u32 input_address; + u32 output_address; + + inline u32 GetPhysicalInputAddress() const { + return input_address * 8; + } + + inline u32 GetPhysicalOutputAddress() const { + return output_address * 8; + } + + union { + u32 output_size; + + BitField< 0, 16, u32> output_width; + BitField<16, 16, u32> output_height; + }; + + union { + u32 input_size; + + BitField< 0, 16, u32> input_width; + BitField<16, 16, u32> input_height; }; - 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; - - u32 command_list_size; - u32 command_list_address; - u32 command_processing_enabled; + union { + u32 flags; + + BitField< 0, 1, u32> flip_data; // flips input data horizontally (TODO) if true + BitField< 8, 3, Format> input_format; + BitField<12, 3, Format> output_format; + BitField<16, 1, u32> output_tiled; // stores output in a tiled format + }; + + u32 unknown; + + // it seems that writing to this field triggers the display transfer + u32 trigger; }; +static_assert(sizeof(Regs::Struct<Regs::DisplayTransfer>) == 0x1C, "Structure size and register block length don't match"); + +template<> +struct Regs::Struct<Regs::CommandProcessor> { + // command list size + u32 size; + + u32 pad0; + + // command list address + u32 address; -extern Registers g_regs; + u32 pad1; + + // it seems that writing to this field triggers command list processing + u32 trigger; +}; +static_assert(sizeof(Regs::Struct<Regs::CommandProcessor>) == 0x14, "Structure size and register block length don't match"); + + +extern RegisterSet<u32, Regs> g_regs; enum { TOP_ASPECT_X = 0x5, @@ -51,23 +176,35 @@ enum { TOP_WIDTH = 400, BOTTOM_WIDTH = 320, - // Physical addresses in FCRAM used by ARM9 applications - these are correct for real hardware - PADDR_FRAMEBUFFER_SEL = 0x20184E59, - PADDR_TOP_LEFT_FRAME1 = 0x20184E60, + // Physical addresses in FCRAM (chosen arbitrarily) + PADDR_TOP_LEFT_FRAME1 = 0x201D4C00, + PADDR_TOP_LEFT_FRAME2 = 0x202D4C00, + PADDR_TOP_RIGHT_FRAME1 = 0x203D4C00, + PADDR_TOP_RIGHT_FRAME2 = 0x204D4C00, + PADDR_SUB_FRAME1 = 0x205D4C00, + PADDR_SUB_FRAME2 = 0x206D4C00, + // Physical addresses in FCRAM used by ARM9 applications +/* 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) - PADDR_VRAM_FRAMEBUFFER_SEL = 0x18184E59, - PADDR_VRAM_TOP_LEFT_FRAME1 = 0x18184E60, - PADDR_VRAM_TOP_LEFT_FRAME2 = 0x181CB370, + PADDR_SUB_FRAME2 = 0x20249CF0,*/ + + // Physical addresses in VRAM + // TODO: These should just be deduced from the ones above + PADDR_VRAM_TOP_LEFT_FRAME1 = 0x181D4C00, + PADDR_VRAM_TOP_LEFT_FRAME2 = 0x182D4C00, + PADDR_VRAM_TOP_RIGHT_FRAME1 = 0x183D4C00, + PADDR_VRAM_TOP_RIGHT_FRAME2 = 0x184D4C00, + PADDR_VRAM_SUB_FRAME1 = 0x185D4C00, + PADDR_VRAM_SUB_FRAME2 = 0x186D4C00, + // Physical addresses in VRAM used by ARM9 applications +/* 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, + PADDR_VRAM_SUB_FRAME2 = 0x18249CF0,*/ }; /// Framebuffer location @@ -79,7 +216,7 @@ enum FramebufferLocation { /** * Sets whether the framebuffers are in the GSP heap (FCRAM) or VRAM - * @param + * @param */ void SetFramebufferLocation(const FramebufferLocation mode); @@ -90,16 +227,18 @@ void SetFramebufferLocation(const FramebufferLocation mode); */ const u8* GetFramebufferPointer(const u32 address); +u32 GetFramebufferAddr(const u32 address); + /** * Gets the location of the framebuffers */ -const FramebufferLocation GetFramebufferLocation(); +FramebufferLocation GetFramebufferLocation(u32 address); template <typename T> -inline void Read(T &var, const u32 addr); +void Read(T &var, const u32 addr); template <typename T> -inline void Write(u32 addr, const T data); +void Write(u32 addr, const T data); /// Update hardware void Update(); |