1 // Copyright 2020 yuzu 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 <memory>
8 #include <unordered_map>
9 #include <vector>
10 #include "common/bit_field.h"
11 #include "common/common_types.h"
12 
13 namespace Tegra {
14 
15 namespace Engines {
16 class Maxwell3D;
17 }
18 
19 namespace Macro {
20 constexpr std::size_t NUM_MACRO_REGISTERS = 8;
21 enum class Operation : u32 {
22     ALU = 0,
23     AddImmediate = 1,
24     ExtractInsert = 2,
25     ExtractShiftLeftImmediate = 3,
26     ExtractShiftLeftRegister = 4,
27     Read = 5,
28     Unused = 6, // This operation doesn't seem to be a valid encoding.
29     Branch = 7,
30 };
31 
32 enum class ALUOperation : u32 {
33     Add = 0,
34     AddWithCarry = 1,
35     Subtract = 2,
36     SubtractWithBorrow = 3,
37     // Operations 4-7 don't seem to be valid encodings.
38     Xor = 8,
39     Or = 9,
40     And = 10,
41     AndNot = 11,
42     Nand = 12
43 };
44 
45 enum class ResultOperation : u32 {
46     IgnoreAndFetch = 0,
47     Move = 1,
48     MoveAndSetMethod = 2,
49     FetchAndSend = 3,
50     MoveAndSend = 4,
51     FetchAndSetMethod = 5,
52     MoveAndSetMethodFetchAndSend = 6,
53     MoveAndSetMethodSend = 7
54 };
55 
56 enum class BranchCondition : u32 {
57     Zero = 0,
58     NotZero = 1,
59 };
60 
61 union Opcode {
62     u32 raw;
63     BitField<0, 3, Operation> operation;
64     BitField<4, 3, ResultOperation> result_operation;
65     BitField<4, 1, BranchCondition> branch_condition;
66     // If set on a branch, then the branch doesn't have a delay slot.
67     BitField<5, 1, u32> branch_annul;
68     BitField<7, 1, u32> is_exit;
69     BitField<8, 3, u32> dst;
70     BitField<11, 3, u32> src_a;
71     BitField<14, 3, u32> src_b;
72     // The signed immediate overlaps the second source operand and the alu operation.
73     BitField<14, 18, s32> immediate;
74 
75     BitField<17, 5, ALUOperation> alu_operation;
76 
77     // Bitfield instructions data
78     BitField<17, 5, u32> bf_src_bit;
79     BitField<22, 5, u32> bf_size;
80     BitField<27, 5, u32> bf_dst_bit;
81 
GetBitfieldMask()82     u32 GetBitfieldMask() const {
83         return (1 << bf_size) - 1;
84     }
85 
GetBranchTarget()86     s32 GetBranchTarget() const {
87         return static_cast<s32>(immediate * sizeof(u32));
88     }
89 };
90 
91 union MethodAddress {
92     u32 raw;
93     BitField<0, 12, u32> address;
94     BitField<12, 6, u32> increment;
95 };
96 
97 } // namespace Macro
98 
99 class HLEMacro;
100 
101 class CachedMacro {
102 public:
103     virtual ~CachedMacro() = default;
104     /**
105      * Executes the macro code with the specified input parameters.
106      *
107      * @param parameters The parameters of the macro
108      * @param method     The method to execute
109      */
110     virtual void Execute(const std::vector<u32>& parameters, u32 method) = 0;
111 };
112 
113 class MacroEngine {
114 public:
115     explicit MacroEngine(Engines::Maxwell3D& maxwell3d);
116     virtual ~MacroEngine();
117 
118     // Store the uploaded macro code to compile them when they're called.
119     void AddCode(u32 method, u32 data);
120 
121     // Compiles the macro if its not in the cache, and executes the compiled macro
122     void Execute(Engines::Maxwell3D& maxwell3d, u32 method, const std::vector<u32>& parameters);
123 
124 protected:
125     virtual std::unique_ptr<CachedMacro> Compile(const std::vector<u32>& code) = 0;
126 
127 private:
128     struct CacheInfo {
129         std::unique_ptr<CachedMacro> lle_program{};
130         std::unique_ptr<CachedMacro> hle_program{};
131         u64 hash{};
132         bool has_hle_program{};
133     };
134 
135     std::unordered_map<u32, CacheInfo> macro_cache;
136     std::unordered_map<u32, std::vector<u32>> uploaded_macro_code;
137     std::unique_ptr<HLEMacro> hle_macros;
138 };
139 
140 std::unique_ptr<MacroEngine> GetMacroEngine(Engines::Maxwell3D& maxwell3d);
141 
142 } // namespace Tegra
143