diff --git a/src/common/common.vcxproj b/src/common/common.vcxproj index 86295a480..1f5c714c3 100644 --- a/src/common/common.vcxproj +++ b/src/common/common.vcxproj @@ -182,6 +182,7 @@ + @@ -221,4 +222,4 @@ - \ No newline at end of file + diff --git a/src/common/common.vcxproj.filters b/src/common/common.vcxproj.filters index 84cfa8837..e8c4ce360 100644 --- a/src/common/common.vcxproj.filters +++ b/src/common/common.vcxproj.filters @@ -4,6 +4,7 @@ + @@ -28,6 +29,7 @@ + @@ -39,7 +41,6 @@ - @@ -65,4 +66,4 @@ - \ No newline at end of file + diff --git a/src/common/register_set.h b/src/common/register_set.h new file mode 100644 index 000000000..0418551b3 --- /dev/null +++ b/src/common/register_set.h @@ -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 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 + * union Struct; + * }; + * + * // Define register set object + * RegisterSet registers; + * + * // define register definition structures + * template<> + * union Regs::Struct { + * 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().some_field = some_value; + * + * For a register which maps to different indices, e.g. a group of similar registers + * registers.Get(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 union, as described above. + * @note RegDefinition::Id needs to have an enum value called NumIds defining the number of registers to be allocated. + */ +template +struct RegisterSet { + // Register IDs + using Id = typename RegDefinition::Id; + + // type used for *this + using ThisType = RegisterSet; + + // Register definition structs, defined in RegDefinition + template + using Struct = typename RegDefinition::template Struct; + + + /* + * Lookup register with the given id and return it as the corresponding structure type. + * @note This just forwards the arguments to Get(Id). + */ + template + const Struct& Get() const { + return Get(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 + Struct& Get() { + return Get(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 + const Struct& Get(const Id& index) const { + const int idx = static_cast(index); + return *reinterpret_cast*>(&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 + Struct& Get(const Id& index) { + return const_cast&>(GetThis().Get(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(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(GetThis()[id]); + } + +private: + /* + * Returns a const reference to "this". + */ + const ThisType& GetThis() const { + return static_cast(*this); + } + + BaseType raw[Id::NumIds]; +}; diff --git a/src/video_core/pica.h b/src/video_core/pica.h index 7cbc45f98..f0fa3aba9 100644 --- a/src/video_core/pica.h +++ b/src/video_core/pica.h @@ -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 + union Struct; }; +static inline Regs::Id VertexAttributeOffset(int n) +{ + return static_cast(0x203 + 3*n); +} + +static inline Regs::Id VertexAttributeInfo0(int n) +{ + return static_cast(0x204 + 3*n); +} + +static inline Regs::Id VertexAttributeInfo1(int n) +{ + return static_cast(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 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 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 { + BitField<0, 24, u32> value; +}; + +template<> +union Regs::Struct { + BitField<0, 24, u32> value; +}; + +template<> +union Regs::Struct { + 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