mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 13:50:03 +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="msg_handler.h" /> | ||||
|     <ClInclude Include="platform.h" /> | ||||
|     <ClInclude Include="register_set.h" /> | ||||
|     <ClInclude Include="scm_rev.h" /> | ||||
|     <ClInclude Include="std_condition_variable.h" /> | ||||
|     <ClInclude Include="std_mutex.h" /> | ||||
|  | @ -221,4 +222,4 @@ | |||
|   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> | ||||
|   <ImportGroup Label="ExtensionTargets"> | ||||
|   </ImportGroup> | ||||
| </Project> | ||||
| </Project> | ||||
|  |  | |||
|  | @ -4,6 +4,7 @@ | |||
|     <ClInclude Include="atomic.h" /> | ||||
|     <ClInclude Include="atomic_gcc.h" /> | ||||
|     <ClInclude Include="atomic_win32.h" /> | ||||
|     <ClInclude Include="bit_field.h" /> | ||||
|     <ClInclude Include="break_points.h" /> | ||||
|     <ClInclude Include="chunk_file.h" /> | ||||
|     <ClInclude Include="common.h" /> | ||||
|  | @ -28,6 +29,7 @@ | |||
|     <ClInclude Include="memory_util.h" /> | ||||
|     <ClInclude Include="msg_handler.h" /> | ||||
|     <ClInclude Include="platform.h" /> | ||||
|     <ClInclude Include="register_set.h" /> | ||||
|     <ClInclude Include="std_condition_variable.h" /> | ||||
|     <ClInclude Include="std_mutex.h" /> | ||||
|     <ClInclude Include="std_thread.h" /> | ||||
|  | @ -39,7 +41,6 @@ | |||
|     <ClInclude Include="utf8.h" /> | ||||
|     <ClInclude Include="symbols.h" /> | ||||
|     <ClInclude Include="scm_rev.h" /> | ||||
|     <ClInclude Include="bit_field.h" /> | ||||
|     <ClInclude Include="thread_queue_list.h" /> | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|  | @ -65,4 +66,4 @@ | |||
|   <ItemGroup> | ||||
|     <Text Include="CMakeLists.txt" /> | ||||
|   </ItemGroup> | ||||
| </Project> | ||||
| </Project> | ||||
|  |  | |||
							
								
								
									
										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,45 +9,122 @@ | |||
| 
 | ||||
| #include "common/bit_field.h" | ||||
| #include "common/common_types.h" | ||||
| #include "common/register_set.h" | ||||
| 
 | ||||
| namespace Pica { | ||||
| 
 | ||||
| enum class CommandId : u32 | ||||
| { | ||||
|     ViewportSizeX            =  0x41, | ||||
|     ViewportInvSizeX         =  0x42, | ||||
|     ViewportSizeY            =  0x43, | ||||
|     ViewportInvSizeY         =  0x44, | ||||
|     ViewportCorner           =  0x68, | ||||
|     DepthBufferFormat        = 0x116, | ||||
|     ColorBufferFormat        = 0x117, | ||||
|     DepthBufferAddress       = 0x11C, | ||||
|     ColorBufferAddress       = 0x11D, | ||||
|     ColorBufferSize          = 0x11E, | ||||
| struct Regs { | ||||
|     enum Id : u32 { | ||||
|         ViewportSizeX              =  0x41, | ||||
|         ViewportInvSizeX           =  0x42, | ||||
|         ViewportSizeY              =  0x43, | ||||
|         ViewportInvSizeY           =  0x44, | ||||
|         ViewportCorner             =  0x68, | ||||
|         DepthBufferFormat          = 0x116, | ||||
|         ColorBufferFormat          = 0x117, | ||||
|         DepthBufferAddress         = 0x11C, | ||||
|         ColorBufferAddress         = 0x11D, | ||||
|         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 { | ||||
|     CommandHeader(u32 h) : hex(h) {} | ||||
| 
 | ||||
|     u32 hex; | ||||
| 
 | ||||
|     BitField< 0, 16, CommandId> cmd_id; | ||||
|     BitField< 0, 16, Regs::Id> cmd_id; | ||||
|     BitField<16,  4, u32> parameter_mask; | ||||
|     BitField<20, 11, u32> extra_data_length; | ||||
|     BitField<31,  1, u32> group_commands; | ||||
| }; | ||||
| 
 | ||||
| static std::map<CommandId, const char*> command_names = { | ||||
|     {CommandId::ViewportSizeX, "ViewportSizeX" }, | ||||
|     {CommandId::ViewportInvSizeX, "ViewportInvSizeX" }, | ||||
|     {CommandId::ViewportSizeY, "ViewportSizeY" }, | ||||
|     {CommandId::ViewportInvSizeY, "ViewportInvSizeY" }, | ||||
|     {CommandId::ViewportCorner, "ViewportCorner" }, | ||||
|     {CommandId::DepthBufferFormat, "DepthBufferFormat" }, | ||||
|     {CommandId::ColorBufferFormat, "ColorBufferFormat" }, | ||||
|     {CommandId::DepthBufferAddress, "DepthBufferAddress" }, | ||||
|     {CommandId::ColorBufferAddress, "ColorBufferAddress" }, | ||||
|     {CommandId::ColorBufferSize, "ColorBufferSize" }, | ||||
| static std::map<Regs::Id, const char*> command_names = { | ||||
|     {Regs::ViewportSizeX, "ViewportSizeX" }, | ||||
|     {Regs::ViewportInvSizeX, "ViewportInvSizeX" }, | ||||
|     {Regs::ViewportSizeY, "ViewportSizeY" }, | ||||
|     {Regs::ViewportInvSizeY, "ViewportInvSizeY" }, | ||||
|     {Regs::ViewportCorner, "ViewportCorner" }, | ||||
|     {Regs::DepthBufferFormat, "DepthBufferFormat" }, | ||||
|     {Regs::ColorBufferFormat, "ColorBufferFormat" }, | ||||
|     {Regs::DepthBufferAddress, "DepthBufferAddress" }, | ||||
|     {Regs::ColorBufferAddress, "ColorBufferAddress" }, | ||||
|     {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