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