1 // Copyright 2014 Citra Emulator Project 2 // Licensed under GPLv2 or any later version 3 // Refer to the license.txt file included. 4 5 #pragma once 6 7 #include <cstddef> 8 #include <type_traits> 9 #include <boost/serialization/access.hpp> 10 #include <boost/serialization/binary_object.hpp> 11 #include "common/assert.h" 12 #include "common/bit_field.h" 13 #include "common/common_funcs.h" 14 #include "common/common_types.h" 15 #include "core/core_timing.h" 16 17 namespace Memory { 18 class MemorySystem; 19 } 20 21 namespace GPU { 22 23 // Measured on hardware to be 2240568 timer cycles or 4481136 ARM11 cycles 24 constexpr u64 frame_ticks = 4481136ull; 25 26 // Refresh rate defined by ratio of ARM11 frequency to ARM11 ticks per frame 27 // (268,111,856) / (4,481,136) = 59.83122493939037Hz 28 constexpr double SCREEN_REFRESH_RATE = BASE_CLOCK_RATE_ARM11 / static_cast<double>(frame_ticks); 29 30 // Returns index corresponding to the Regs member labeled by field_name 31 #define GPU_REG_INDEX(field_name) (offsetof(GPU::Regs, field_name) / sizeof(u32)) 32 33 // Returns index corresponding to the Regs::FramebufferConfig labeled by field_name 34 // screen_id is a subscript for Regs::framebuffer_config 35 #define GPU_FRAMEBUFFER_REG_INDEX(screen_id, field_name) \ 36 ((offsetof(GPU::Regs, framebuffer_config) + \ 37 sizeof(GPU::Regs::FramebufferConfig) * (screen_id) + \ 38 offsetof(GPU::Regs::FramebufferConfig, field_name)) / \ 39 sizeof(u32)) 40 41 // MMIO region 0x1EFxxxxx 42 struct Regs { 43 44 // helper macro to make sure the defined structures are of the expected size. 45 #define ASSERT_MEMBER_SIZE(name, size_in_bytes) \ 46 static_assert(sizeof(name) == size_in_bytes, \ 47 "Structure size and register block length don't match") 48 49 // Components are laid out in reverse byte order, most significant bits first. 50 enum class PixelFormat : u32 { 51 RGBA8 = 0, 52 RGB8 = 1, 53 RGB565 = 2, 54 RGB5A1 = 3, 55 RGBA4 = 4, 56 }; 57 58 /** 59 * Returns the number of bytes per pixel. 60 */ BytesPerPixelRegs61 static int BytesPerPixel(PixelFormat format) { 62 switch (format) { 63 case PixelFormat::RGBA8: 64 return 4; 65 case PixelFormat::RGB8: 66 return 3; 67 case PixelFormat::RGB565: 68 case PixelFormat::RGB5A1: 69 case PixelFormat::RGBA4: 70 return 2; 71 } 72 73 UNREACHABLE(); 74 } 75 76 INSERT_PADDING_WORDS(0x4); 77 78 struct MemoryFillConfig { 79 u32 address_start; 80 u32 address_end; 81 82 union { 83 u32 value_32bit; 84 85 BitField<0, 16, u32> value_16bit; 86 87 // TODO: Verify component order 88 BitField<0, 8, u32> value_24bit_r; 89 BitField<8, 8, u32> value_24bit_g; 90 BitField<16, 8, u32> value_24bit_b; 91 }; 92 93 union { 94 u32 control; 95 96 // Setting this field to 1 triggers the memory fill. 97 // This field also acts as a status flag, and gets reset to 0 upon completion. 98 BitField<0, 1, u32> trigger; 99 100 // Set to 1 upon completion. 101 BitField<1, 1, u32> finished; 102 103 // If both of these bits are unset, then it will fill the memory with a 16 bit value 104 // 1: fill with 24-bit wide values 105 BitField<8, 1, u32> fill_24bit; 106 // 1: fill with 32-bit wide values 107 BitField<9, 1, u32> fill_32bit; 108 }; 109 GetStartAddressRegs::MemoryFillConfig110 inline u32 GetStartAddress() const { 111 return DecodeAddressRegister(address_start); 112 } 113 GetEndAddressRegs::MemoryFillConfig114 inline u32 GetEndAddress() const { 115 return DecodeAddressRegister(address_end); 116 } 117 } memory_fill_config[2]; 118 ASSERT_MEMBER_SIZE(memory_fill_config[0], 0x10); 119 120 INSERT_PADDING_WORDS(0x10b); 121 122 struct FramebufferConfig { 123 union { 124 u32 size; 125 126 BitField<0, 16, u32> width; 127 BitField<16, 16, u32> height; 128 }; 129 130 INSERT_PADDING_WORDS(0x2); 131 132 u32 address_left1; 133 u32 address_left2; 134 135 union { 136 u32 format; 137 138 BitField<0, 3, PixelFormat> color_format; 139 }; 140 141 INSERT_PADDING_WORDS(0x1); 142 143 union { 144 u32 active_fb; 145 146 // 0: Use parameters ending with "1" 147 // 1: Use parameters ending with "2" 148 BitField<0, 1, u32> second_fb_active; 149 }; 150 151 INSERT_PADDING_WORDS(0x5); 152 153 // Distance between two pixel rows, in bytes 154 u32 stride; 155 156 u32 address_right1; 157 u32 address_right2; 158 159 INSERT_PADDING_WORDS(0x30); 160 } framebuffer_config[2]; 161 ASSERT_MEMBER_SIZE(framebuffer_config[0], 0x100); 162 163 INSERT_PADDING_WORDS(0x169); 164 165 struct DisplayTransferConfig { 166 u32 input_address; 167 u32 output_address; 168 GetPhysicalInputAddressRegs::DisplayTransferConfig169 inline u32 GetPhysicalInputAddress() const { 170 return DecodeAddressRegister(input_address); 171 } 172 GetPhysicalOutputAddressRegs::DisplayTransferConfig173 inline u32 GetPhysicalOutputAddress() const { 174 return DecodeAddressRegister(output_address); 175 } 176 177 union { 178 u32 output_size; 179 180 BitField<0, 16, u32> output_width; 181 BitField<16, 16, u32> output_height; 182 }; 183 184 union { 185 u32 input_size; 186 187 BitField<0, 16, u32> input_width; 188 BitField<16, 16, u32> input_height; 189 }; 190 191 enum ScalingMode : u32 { 192 NoScale = 0, // Doesn't scale the image 193 ScaleX = 1, // Downscales the image in half in the X axis and applies a box filter 194 ScaleXY = 195 2, // Downscales the image in half in both the X and Y axes and applies a box filter 196 }; 197 198 union { 199 u32 flags; 200 201 BitField<0, 1, u32> flip_vertically; // flips input data vertically 202 BitField<1, 1, u32> input_linear; // Converts from linear to tiled format 203 BitField<2, 1, u32> crop_input_lines; 204 BitField<3, 1, u32> is_texture_copy; // Copies the data without performing any 205 // processing and respecting texture copy fields 206 BitField<5, 1, u32> dont_swizzle; 207 BitField<8, 3, PixelFormat> input_format; 208 BitField<12, 3, PixelFormat> output_format; 209 /// Uses some kind of 32x32 block swizzling mode, instead of the usual 8x8 one. 210 BitField<16, 1, u32> block_32; // TODO(yuriks): unimplemented 211 BitField<24, 2, ScalingMode> scaling; // Determines the scaling mode of the transfer 212 }; 213 214 INSERT_PADDING_WORDS(0x1); 215 216 // it seems that writing to this field triggers the display transfer 217 u32 trigger; 218 219 INSERT_PADDING_WORDS(0x1); 220 221 struct { 222 u32 size; // The lower 4 bits are ignored 223 224 union { 225 u32 input_size; 226 227 BitField<0, 16, u32> input_width; 228 BitField<16, 16, u32> input_gap; 229 }; 230 231 union { 232 u32 output_size; 233 234 BitField<0, 16, u32> output_width; 235 BitField<16, 16, u32> output_gap; 236 }; 237 } texture_copy; 238 } display_transfer_config; 239 ASSERT_MEMBER_SIZE(display_transfer_config, 0x2c); 240 241 INSERT_PADDING_WORDS(0x32D); 242 243 struct { 244 // command list size (in bytes) 245 u32 size; 246 247 INSERT_PADDING_WORDS(0x1); 248 249 // command list address 250 u32 address; 251 252 INSERT_PADDING_WORDS(0x1); 253 254 // it seems that writing to this field triggers command list processing 255 u32 trigger; 256 GetPhysicalAddressRegs::__anon449306570c08257 inline u32 GetPhysicalAddress() const { 258 return DecodeAddressRegister(address); 259 } 260 } command_processor_config; 261 ASSERT_MEMBER_SIZE(command_processor_config, 0x14); 262 263 INSERT_PADDING_WORDS(0x9c3); 264 NumIdsRegs265 static constexpr std::size_t NumIds() { 266 return sizeof(Regs) / sizeof(u32); 267 } 268 269 const u32& operator[](int index) const { 270 const u32* content = reinterpret_cast<const u32*>(this); 271 return content[index]; 272 } 273 274 u32& operator[](int index) { 275 u32* content = reinterpret_cast<u32*>(this); 276 return content[index]; 277 } 278 279 #undef ASSERT_MEMBER_SIZE 280 281 private: 282 /* 283 * Most physical addresses which GPU registers refer to are 8-byte aligned. 284 * This function should be used to get the address from a raw register value. 285 */ DecodeAddressRegisterRegs286 static inline u32 DecodeAddressRegister(u32 register_value) { 287 return register_value * 8; 288 } 289 290 template <class Archive> serializeRegs291 void serialize(Archive& ar, const unsigned int) { 292 ar& boost::serialization::make_binary_object(this, sizeof(Regs)); 293 } 294 friend class boost::serialization::access; 295 }; 296 static_assert(std::is_standard_layout<Regs>::value, "Structure does not use standard layout"); 297 298 #define ASSERT_REG_POSITION(field_name, position) \ 299 static_assert(offsetof(Regs, field_name) == position * 4, \ 300 "Field " #field_name " has invalid position") 301 302 ASSERT_REG_POSITION(memory_fill_config[0], 0x00004); 303 ASSERT_REG_POSITION(memory_fill_config[1], 0x00008); 304 ASSERT_REG_POSITION(framebuffer_config[0], 0x00117); 305 ASSERT_REG_POSITION(framebuffer_config[1], 0x00157); 306 ASSERT_REG_POSITION(display_transfer_config, 0x00300); 307 ASSERT_REG_POSITION(command_processor_config, 0x00638); 308 309 #undef ASSERT_REG_POSITION 310 311 // The total number of registers is chosen arbitrarily, but let's make sure it's not some odd value 312 // anyway. 313 static_assert(sizeof(Regs) == 0x1000 * sizeof(u32), "Invalid total size of register set"); 314 315 extern Regs g_regs; 316 317 template <typename T> 318 void Read(T& var, const u32 addr); 319 320 template <typename T> 321 void Write(u32 addr, const T data); 322 323 /// Initialize hardware 324 void Init(Memory::MemorySystem& memory); 325 326 /// Shutdown hardware 327 void Shutdown(); 328 329 } // namespace GPU 330