skyline/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell/macro_interpreter.h

149 lines
4.6 KiB
C++

// SPDX-License-Identifier: MPL-2.0
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
#pragma once
#include <common.h>
namespace skyline::soc::gm20b::engine::maxwell3d {
class Maxwell3D; // A forward declaration of Maxwell3D as we don't want to import it here
/**
* @brief The MacroInterpreter class handles interpreting macros. Macros are small programs that run on the GPU and are used for things like instanced rendering
*/
class MacroInterpreter {
private:
#pragma pack(push, 1)
union Opcode {
u32 raw;
enum class Operation : u8 {
AluRegister = 0,
AddImmediate = 1,
BitfieldReplace = 2,
BitfieldExtractShiftLeftImmediate = 3,
BitfieldExtractShiftLeftRegister = 4,
ReadImmediate = 5,
Branch = 7,
};
enum class AssignmentOperation : u8 {
IgnoreAndFetch = 0,
Move = 1,
MoveAndSetMethod = 2,
FetchAndSend = 3,
MoveAndSend = 4,
FetchAndSetMethod = 5,
MoveAndSetMethodThenFetchAndSend = 6,
MoveAndSetMethodThenSendHigh = 7,
};
enum class AluOperation : u8 {
Add = 0,
AddWithCarry = 1,
Subtract = 2,
SubtractWithBorrow = 3,
BitwiseXor = 8,
BitwiseOr = 9,
BitwiseAnd = 10,
BitwiseAndNot = 11,
BitwiseNand = 12,
};
enum class BranchCondition : u8 {
Zero = 0,
NonZero = 1,
};
struct {
Operation operation : 3;
u8 _pad0_ : 1;
AssignmentOperation assignmentOperation : 3;
};
struct {
u8 _pad1_ : 4;
BranchCondition branchCondition : 1;
bool noDelay : 1;
u8 _pad2_ : 1;
u8 exit : 1;
u8 dest : 3;
u8 srcA : 3;
u8 srcB : 3;
AluOperation aluOperation : 5;
};
struct {
u16 _pad3_ : 14;
i32 immediate : 18;
};
struct {
u32 _pad_ : 17;
u8 srcBit : 5;
u8 size : 5;
u8 destBit : 5;
u32 GetMask() {
return (1 << size) - 1;
}
} bitfield;
};
#pragma pack(pop)
static_assert(sizeof(Opcode) == sizeof(u32));
/**
* @brief Metadata about the Maxwell 3D method to be called in 'Send'
*/
union MethodAddress {
u32 raw;
struct {
u16 address : 12;
u8 increment : 6;
};
};
Maxwell3D &maxwell3D; //!< A reference to the parent engine object
Opcode *opcode{}; //!< A pointer to the instruction that is currently being executed
std::array<u32, 8> registers{}; //!< The state of all the general-purpose registers in the macro interpreter
const u32 *argument{}; //!< A pointer to the argument buffer for the program, it is read from sequentially
MethodAddress methodAddress{};
bool carryFlag{}; //!< A flag representing if an arithmetic operation has set the most significant bit
/**
* @brief Steps forward one macro instruction, including delay slots
* @param delayedOpcode The target opcode to be jumped to after executing the instruction
*/
bool Step(Opcode *delayedOpcode = nullptr);
/**
* @brief Performs an ALU operation on the given source values and returns the result as a u32
*/
u32 HandleAlu(Opcode::AluOperation operation, u32 srcA, u32 srcB);
/**
* @brief Handles an opcode's assignment operation
*/
void HandleAssignment(Opcode::AssignmentOperation operation, u8 reg, u32 result);
/**
* @brief Sends a method call to the Maxwell 3D
*/
void Send(u32 argument);
/**
* @brief Writes to the specified register with sanity checking
*/
void WriteRegister(u8 reg, u32 value);
public:
MacroInterpreter(Maxwell3D &maxwell3D) : maxwell3D(maxwell3D) {}
/**
* @brief Executes a GPU macro from macro memory with the given arguments
*/
void Execute(size_t offset, const std::vector<u32> &args);
};
}