mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	Pica: Use some template magic to define register structures efficiently.
This commit is contained in:
		
							parent
							
								
									f82410e633
								
							
						
					
					
						commit
						4c2bff61e5
					
				
					 4 changed files with 268 additions and 28 deletions
				
			
		|  | @ -182,6 +182,7 @@ | ||||||
|     <ClInclude Include="mem_arena.h" /> |     <ClInclude Include="mem_arena.h" /> | ||||||
|     <ClInclude Include="msg_handler.h" /> |     <ClInclude Include="msg_handler.h" /> | ||||||
|     <ClInclude Include="platform.h" /> |     <ClInclude Include="platform.h" /> | ||||||
|  |     <ClInclude Include="register_set.h" /> | ||||||
|     <ClInclude Include="scm_rev.h" /> |     <ClInclude Include="scm_rev.h" /> | ||||||
|     <ClInclude Include="std_condition_variable.h" /> |     <ClInclude Include="std_condition_variable.h" /> | ||||||
|     <ClInclude Include="std_mutex.h" /> |     <ClInclude Include="std_mutex.h" /> | ||||||
|  |  | ||||||
|  | @ -4,6 +4,7 @@ | ||||||
|     <ClInclude Include="atomic.h" /> |     <ClInclude Include="atomic.h" /> | ||||||
|     <ClInclude Include="atomic_gcc.h" /> |     <ClInclude Include="atomic_gcc.h" /> | ||||||
|     <ClInclude Include="atomic_win32.h" /> |     <ClInclude Include="atomic_win32.h" /> | ||||||
|  |     <ClInclude Include="bit_field.h" /> | ||||||
|     <ClInclude Include="break_points.h" /> |     <ClInclude Include="break_points.h" /> | ||||||
|     <ClInclude Include="chunk_file.h" /> |     <ClInclude Include="chunk_file.h" /> | ||||||
|     <ClInclude Include="common.h" /> |     <ClInclude Include="common.h" /> | ||||||
|  | @ -28,6 +29,7 @@ | ||||||
|     <ClInclude Include="memory_util.h" /> |     <ClInclude Include="memory_util.h" /> | ||||||
|     <ClInclude Include="msg_handler.h" /> |     <ClInclude Include="msg_handler.h" /> | ||||||
|     <ClInclude Include="platform.h" /> |     <ClInclude Include="platform.h" /> | ||||||
|  |     <ClInclude Include="register_set.h" /> | ||||||
|     <ClInclude Include="std_condition_variable.h" /> |     <ClInclude Include="std_condition_variable.h" /> | ||||||
|     <ClInclude Include="std_mutex.h" /> |     <ClInclude Include="std_mutex.h" /> | ||||||
|     <ClInclude Include="std_thread.h" /> |     <ClInclude Include="std_thread.h" /> | ||||||
|  | @ -39,7 +41,6 @@ | ||||||
|     <ClInclude Include="utf8.h" /> |     <ClInclude Include="utf8.h" /> | ||||||
|     <ClInclude Include="symbols.h" /> |     <ClInclude Include="symbols.h" /> | ||||||
|     <ClInclude Include="scm_rev.h" /> |     <ClInclude Include="scm_rev.h" /> | ||||||
|     <ClInclude Include="bit_field.h" /> |  | ||||||
|     <ClInclude Include="thread_queue_list.h" /> |     <ClInclude Include="thread_queue_list.h" /> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|  |  | ||||||
							
								
								
									
										161
									
								
								src/common/register_set.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										161
									
								
								src/common/register_set.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,161 @@ | ||||||
|  | // Copyright 2014 Citra Emulator Project
 | ||||||
|  | // Licensed under GPLv2
 | ||||||
|  | // Refer to the license.txt file included.
 | ||||||
|  | 
 | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | // Copyright 2014 Tony Wasserka
 | ||||||
|  | // All rights reserved.
 | ||||||
|  | //
 | ||||||
|  | // Redistribution and use in source and binary forms, with or without
 | ||||||
|  | // modification, are permitted provided that the following conditions are met:
 | ||||||
|  | //
 | ||||||
|  | //     * Redistributions of source code must retain the above copyright
 | ||||||
|  | //       notice, this list of conditions and the following disclaimer.
 | ||||||
|  | //     * Redistributions in binary form must reproduce the above copyright
 | ||||||
|  | //       notice, this list of conditions and the following disclaimer in the
 | ||||||
|  | //       documentation and/or other materials provided with the distribution.
 | ||||||
|  | //     * Neither the name of the owner nor the names of its contributors may
 | ||||||
|  | //       be used to endorse or promote products derived from this software
 | ||||||
|  | //       without specific prior written permission.
 | ||||||
|  | //
 | ||||||
|  | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | ||||||
|  | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | ||||||
|  | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | ||||||
|  | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | ||||||
|  | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | ||||||
|  | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | ||||||
|  | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | ||||||
|  | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | ||||||
|  | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | ||||||
|  | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | ||||||
|  | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Standardized way to define a group of registers and corresponding data structures. To define | ||||||
|  |  * a new register set, first define struct containing an enumeration called "Id" containing | ||||||
|  |  * all register IDs and a template union called "Struct". Specialize the Struct union for any | ||||||
|  |  * register ID which needs to be accessed in a specialized way. You can then declare the object | ||||||
|  |  * containing all register values using the RegisterSet<BaseType, DefiningStruct> type, where | ||||||
|  |  * BaseType is the underlying type of each register (e.g. u32). | ||||||
|  |  * Of course, you'll usually want to implement the Struct template such that they are of the same | ||||||
|  |  * size as BaseType. However, it's also possible to make it larger, e.g. when you want to describe | ||||||
|  |  * multiple registers with the same structure. | ||||||
|  |  * | ||||||
|  |  * Example: | ||||||
|  |  * | ||||||
|  |  *     struct Regs { | ||||||
|  |  *         enum Id : u32 { | ||||||
|  |  *             Value1 = 0, | ||||||
|  |  *             Value2 = 1, | ||||||
|  |  *             Value3 = 2, | ||||||
|  |  *             NumIds = 3 | ||||||
|  |  *         }; | ||||||
|  |  * | ||||||
|  |  *         // declare register definition structures
 | ||||||
|  |  *         template<Id id> | ||||||
|  |  *         union Struct; | ||||||
|  |  *     }; | ||||||
|  |  * | ||||||
|  |  *     // Define register set object
 | ||||||
|  |  *     RegisterSet<u32, CommandIds> registers; | ||||||
|  |  * | ||||||
|  |  *     // define register definition structures
 | ||||||
|  |  *     template<> | ||||||
|  |  *     union Regs::Struct<Regs::Value1> { | ||||||
|  |  *         BitField<0, 4, u32> some_field; | ||||||
|  |  *         BitField<4, 3, u32> some_other_field; | ||||||
|  |  *     }; | ||||||
|  |  * | ||||||
|  |  * Usage in external code (within SomeNamespace scope): | ||||||
|  |  * | ||||||
|  |  *     For a register which maps to a single index: | ||||||
|  |  *     registers.Get<Regs::Value1>().some_field = some_value; | ||||||
|  |  * | ||||||
|  |  *      For a register which maps to different indices, e.g. a group of similar registers | ||||||
|  |  *     registers.Get<Regs::Value1>(index).some_field = some_value; | ||||||
|  |  * | ||||||
|  |  * | ||||||
|  |  * @tparam BaseType Base type used for storing individual registers, e.g. u32 | ||||||
|  |  * @tparam RegDefinition Class defining an enumeration called "Id" and a template<Id id> union, as described above. | ||||||
|  |  * @note RegDefinition::Id needs to have an enum value called NumIds defining the number of registers to be allocated. | ||||||
|  |  */ | ||||||
|  | template<typename BaseType, typename RegDefinition> | ||||||
|  | struct RegisterSet { | ||||||
|  |     // Register IDs
 | ||||||
|  |     using Id = typename RegDefinition::Id; | ||||||
|  | 
 | ||||||
|  |     // type used for *this
 | ||||||
|  |     using ThisType = RegisterSet<BaseType, RegDefinition>; | ||||||
|  | 
 | ||||||
|  |     // Register definition structs, defined in RegDefinition
 | ||||||
|  |     template<Id id> | ||||||
|  |     using Struct = typename RegDefinition::template Struct<id>; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     /*
 | ||||||
|  |      * Lookup register with the given id and return it as the corresponding structure type. | ||||||
|  |      * @note This just forwards the arguments to Get(Id). | ||||||
|  |      */ | ||||||
|  |     template<Id id> | ||||||
|  |     const Struct<id>& Get() const { | ||||||
|  |         return Get<id>(id); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /*
 | ||||||
|  |      * Lookup register with the given id and return it as the corresponding structure type. | ||||||
|  |      * @note This just forwards the arguments to Get(Id). | ||||||
|  |      */ | ||||||
|  |     template<Id id> | ||||||
|  |     Struct<id>& Get() { | ||||||
|  |         return Get<id>(id); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /*
 | ||||||
|  |      * Lookup register with the given index and return it as the corresponding structure type. | ||||||
|  |      * @todo Is this portable with regards to structures larger than BaseType? | ||||||
|  |      * @note if index==id, you don't need to specify the function parameter. | ||||||
|  |      */ | ||||||
|  |     template<Id id> | ||||||
|  |     const Struct<id>& Get(const Id& index) const { | ||||||
|  |         const int idx = static_cast<size_t>(index); | ||||||
|  |         return *reinterpret_cast<const Struct<id>*>(&raw[idx]); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /*
 | ||||||
|  |      * Lookup register with the given index and return it as the corresponding structure type. | ||||||
|  |      * @note This just forwards the arguments to the const version of Get(Id). | ||||||
|  |      * @note if index==id, you don't need to specify the function parameter. | ||||||
|  |      */ | ||||||
|  |     template<Id id> | ||||||
|  |     Struct<id>& Get(const Id& index) { | ||||||
|  |         return const_cast<Struct<id>&>(GetThis().Get<id>(index)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /*
 | ||||||
|  |      * Plain array access. | ||||||
|  |      * @note If you want to have this casted to a register defininition struct, use Get() instead. | ||||||
|  |      */ | ||||||
|  |     const BaseType& operator[] (const Id& id) const { | ||||||
|  |         return raw[static_cast<size_t>(id)]; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /*
 | ||||||
|  |      * Plain array access. | ||||||
|  |      * @note If you want to have this casted to a register defininition struct, use Get() instead. | ||||||
|  |      * @note This operator just forwards its argument to the const version. | ||||||
|  |      */ | ||||||
|  |     BaseType& operator[] (const Id& id) { | ||||||
|  |         return const_cast<BaseType&>(GetThis()[id]); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     /*
 | ||||||
|  |      * Returns a const reference to "this". | ||||||
|  |      */ | ||||||
|  |     const ThisType& GetThis() const { | ||||||
|  |         return static_cast<const ThisType&>(*this); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     BaseType raw[Id::NumIds]; | ||||||
|  | }; | ||||||
|  | @ -9,11 +9,12 @@ | ||||||
| 
 | 
 | ||||||
| #include "common/bit_field.h" | #include "common/bit_field.h" | ||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
|  | #include "common/register_set.h" | ||||||
| 
 | 
 | ||||||
| namespace Pica { | namespace Pica { | ||||||
| 
 | 
 | ||||||
| enum class CommandId : u32 | struct Regs { | ||||||
| { |     enum Id : u32 { | ||||||
|         ViewportSizeX              =  0x41, |         ViewportSizeX              =  0x41, | ||||||
|         ViewportInvSizeX           =  0x42, |         ViewportInvSizeX           =  0x42, | ||||||
|         ViewportSizeY              =  0x43, |         ViewportSizeY              =  0x43, | ||||||
|  | @ -24,30 +25,106 @@ enum class CommandId : u32 | ||||||
|         DepthBufferAddress         = 0x11C, |         DepthBufferAddress         = 0x11C, | ||||||
|         ColorBufferAddress         = 0x11D, |         ColorBufferAddress         = 0x11D, | ||||||
|         ColorBufferSize            = 0x11E, |         ColorBufferSize            = 0x11E, | ||||||
|  | 
 | ||||||
|  |         VertexArrayBaseAddr        = 0x200, | ||||||
|  |         VertexDescriptor           = 0x201, // 0x202
 | ||||||
|  |         VertexAttributeOffset      = 0x203, // 0x206,0x209,0x20C,0x20F,0x212,0x215,0x218,0x21B,0x21E,0x221,0x224
 | ||||||
|  |         VertexAttributeInfo0       = 0x204, // 0x207,0x20A,0x20D,0x210,0x213,0x216,0x219,0x21C,0x21F,0x222,0x225
 | ||||||
|  |         VertexAttributeInfo1       = 0x205, // 0x208,0x20B,0x20E,0x211,0x214,0x217,0x21A,0x21D,0x220,0x223,0x226
 | ||||||
|  | 
 | ||||||
|  |         NumIds                     = 0x300, | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|  |     template<Id id> | ||||||
|  |     union Struct; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static inline Regs::Id VertexAttributeOffset(int n) | ||||||
|  | { | ||||||
|  |     return static_cast<Regs::Id>(0x203 + 3*n); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline Regs::Id VertexAttributeInfo0(int n) | ||||||
|  | { | ||||||
|  |     return static_cast<Regs::Id>(0x204 + 3*n); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline Regs::Id VertexAttributeInfo1(int n) | ||||||
|  | { | ||||||
|  |     return static_cast<Regs::Id>(0x205 + 3*n); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| union CommandHeader { | union CommandHeader { | ||||||
|     CommandHeader(u32 h) : hex(h) {} |     CommandHeader(u32 h) : hex(h) {} | ||||||
| 
 | 
 | ||||||
|     u32 hex; |     u32 hex; | ||||||
| 
 | 
 | ||||||
|     BitField< 0, 16, CommandId> cmd_id; |     BitField< 0, 16, Regs::Id> cmd_id; | ||||||
|     BitField<16,  4, u32> parameter_mask; |     BitField<16,  4, u32> parameter_mask; | ||||||
|     BitField<20, 11, u32> extra_data_length; |     BitField<20, 11, u32> extra_data_length; | ||||||
|     BitField<31,  1, u32> group_commands; |     BitField<31,  1, u32> group_commands; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static std::map<CommandId, const char*> command_names = { | static std::map<Regs::Id, const char*> command_names = { | ||||||
|     {CommandId::ViewportSizeX, "ViewportSizeX" }, |     {Regs::ViewportSizeX, "ViewportSizeX" }, | ||||||
|     {CommandId::ViewportInvSizeX, "ViewportInvSizeX" }, |     {Regs::ViewportInvSizeX, "ViewportInvSizeX" }, | ||||||
|     {CommandId::ViewportSizeY, "ViewportSizeY" }, |     {Regs::ViewportSizeY, "ViewportSizeY" }, | ||||||
|     {CommandId::ViewportInvSizeY, "ViewportInvSizeY" }, |     {Regs::ViewportInvSizeY, "ViewportInvSizeY" }, | ||||||
|     {CommandId::ViewportCorner, "ViewportCorner" }, |     {Regs::ViewportCorner, "ViewportCorner" }, | ||||||
|     {CommandId::DepthBufferFormat, "DepthBufferFormat" }, |     {Regs::DepthBufferFormat, "DepthBufferFormat" }, | ||||||
|     {CommandId::ColorBufferFormat, "ColorBufferFormat" }, |     {Regs::ColorBufferFormat, "ColorBufferFormat" }, | ||||||
|     {CommandId::DepthBufferAddress, "DepthBufferAddress" }, |     {Regs::DepthBufferAddress, "DepthBufferAddress" }, | ||||||
|     {CommandId::ColorBufferAddress, "ColorBufferAddress" }, |     {Regs::ColorBufferAddress, "ColorBufferAddress" }, | ||||||
|     {CommandId::ColorBufferSize, "ColorBufferSize" }, |     {Regs::ColorBufferSize, "ColorBufferSize" }, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } | template<> | ||||||
|  | union Regs::Struct<Regs::ViewportSizeX> { | ||||||
|  |     BitField<0, 24, u32> value; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | template<> | ||||||
|  | union Regs::Struct<Regs::ViewportSizeY> { | ||||||
|  |     BitField<0, 24, u32> value; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | template<> | ||||||
|  | union Regs::Struct<Regs::VertexDescriptor> { | ||||||
|  |     enum class Format : u64 { | ||||||
|  |         BYTE = 0, | ||||||
|  |         UBYTE = 1, | ||||||
|  |         SHORT = 2, | ||||||
|  |         FLOAT = 3, | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     BitField< 0,  2, Format> format0; | ||||||
|  |     BitField< 2,  2, u64> size0;      // number of elements minus 1
 | ||||||
|  |     BitField< 4,  2, Format> format1; | ||||||
|  |     BitField< 6,  2, u64> size1; | ||||||
|  |     BitField< 8,  2, Format> format2; | ||||||
|  |     BitField<10,  2, u64> size2; | ||||||
|  |     BitField<12,  2, Format> format3; | ||||||
|  |     BitField<14,  2, u64> size3; | ||||||
|  |     BitField<16,  2, Format> format4; | ||||||
|  |     BitField<18,  2, u64> size4; | ||||||
|  |     BitField<20,  2, Format> format5; | ||||||
|  |     BitField<22,  2, u64> size5; | ||||||
|  |     BitField<24,  2, Format> format6; | ||||||
|  |     BitField<26,  2, u64> size6; | ||||||
|  |     BitField<28,  2, Format> format7; | ||||||
|  |     BitField<30,  2, u64> size7; | ||||||
|  |     BitField<32,  2, Format> format8; | ||||||
|  |     BitField<34,  2, u64> size8; | ||||||
|  |     BitField<36,  2, Format> format9; | ||||||
|  |     BitField<38,  2, u64> size9; | ||||||
|  |     BitField<40,  2, Format> format10; | ||||||
|  |     BitField<42,  2, u64> size10; | ||||||
|  |     BitField<44,  2, Format> format11; | ||||||
|  |     BitField<46,  2, u64> size11; | ||||||
|  | 
 | ||||||
|  |     BitField<48, 12, u64> attribute_mask; | ||||||
|  |     BitField<60,  4, u64> num_attributes; // number of total attributes minus 1
 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | } // namespace
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue