macro_interpreter.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include <array>
  4. #include <optional>
  5. #include "common/assert.h"
  6. #include "common/logging/log.h"
  7. #include "common/microprofile.h"
  8. #include "video_core/engines/maxwell_3d.h"
  9. #include "video_core/macro/macro_interpreter.h"
  10. MICROPROFILE_DEFINE(MacroInterp, "GPU", "Execute macro interpreter", MP_RGB(128, 128, 192));
  11. namespace Tegra {
  12. namespace {
  13. class MacroInterpreterImpl final : public CachedMacro {
  14. public:
  15. explicit MacroInterpreterImpl(Engines::Maxwell3D& maxwell3d_, const std::vector<u32>& code_)
  16. : maxwell3d{maxwell3d_}, code{code_} {}
  17. void Execute(const std::vector<u32>& params, u32 method) override;
  18. private:
  19. /// Resets the execution engine state, zeroing registers, etc.
  20. void Reset();
  21. /**
  22. * Executes a single macro instruction located at the current program counter. Returns whether
  23. * the interpreter should keep running.
  24. *
  25. * @param is_delay_slot Whether the current step is being executed due to a delay slot in a
  26. * previous instruction.
  27. */
  28. bool Step(bool is_delay_slot);
  29. /// Calculates the result of an ALU operation. src_a OP src_b;
  30. u32 GetALUResult(Macro::ALUOperation operation, u32 src_a, u32 src_b);
  31. /// Performs the result operation on the input result and stores it in the specified register
  32. /// (if necessary).
  33. void ProcessResult(Macro::ResultOperation operation, u32 reg, u32 result);
  34. /// Evaluates the branch condition and returns whether the branch should be taken or not.
  35. bool EvaluateBranchCondition(Macro::BranchCondition cond, u32 value) const;
  36. /// Reads an opcode at the current program counter location.
  37. Macro::Opcode GetOpcode() const;
  38. /// Returns the specified register's value. Register 0 is hardcoded to always return 0.
  39. u32 GetRegister(u32 register_id) const;
  40. /// Sets the register to the input value.
  41. void SetRegister(u32 register_id, u32 value);
  42. /// Sets the method address to use for the next Send instruction.
  43. void SetMethodAddress(u32 address);
  44. /// Calls a GPU Engine method with the input parameter.
  45. void Send(u32 value);
  46. /// Reads a GPU register located at the method address.
  47. u32 Read(u32 method) const;
  48. /// Returns the next parameter in the parameter queue.
  49. u32 FetchParameter();
  50. Engines::Maxwell3D& maxwell3d;
  51. /// Current program counter
  52. u32 pc{};
  53. /// Program counter to execute at after the delay slot is executed.
  54. std::optional<u32> delayed_pc;
  55. /// General purpose macro registers.
  56. std::array<u32, Macro::NUM_MACRO_REGISTERS> registers = {};
  57. /// Method address to use for the next Send instruction.
  58. Macro::MethodAddress method_address = {};
  59. /// Input parameters of the current macro.
  60. std::unique_ptr<u32[]> parameters;
  61. std::size_t num_parameters = 0;
  62. std::size_t parameters_capacity = 0;
  63. /// Index of the next parameter that will be fetched by the 'parm' instruction.
  64. u32 next_parameter_index = 0;
  65. bool carry_flag = false;
  66. const std::vector<u32>& code;
  67. };
  68. void MacroInterpreterImpl::Execute(const std::vector<u32>& params, u32 method) {
  69. MICROPROFILE_SCOPE(MacroInterp);
  70. Reset();
  71. registers[1] = params[0];
  72. num_parameters = params.size();
  73. if (num_parameters > parameters_capacity) {
  74. parameters_capacity = num_parameters;
  75. parameters = std::make_unique<u32[]>(num_parameters);
  76. }
  77. std::memcpy(parameters.get(), params.data(), num_parameters * sizeof(u32));
  78. // Execute the code until we hit an exit condition.
  79. bool keep_executing = true;
  80. while (keep_executing) {
  81. keep_executing = Step(false);
  82. }
  83. // Assert the the macro used all the input parameters
  84. ASSERT(next_parameter_index == num_parameters);
  85. }
  86. void MacroInterpreterImpl::Reset() {
  87. registers = {};
  88. pc = 0;
  89. delayed_pc = {};
  90. method_address.raw = 0;
  91. num_parameters = 0;
  92. // The next parameter index starts at 1, because $r1 already has the value of the first
  93. // parameter.
  94. next_parameter_index = 1;
  95. carry_flag = false;
  96. }
  97. bool MacroInterpreterImpl::Step(bool is_delay_slot) {
  98. u32 base_address = pc;
  99. Macro::Opcode opcode = GetOpcode();
  100. pc += 4;
  101. // Update the program counter if we were delayed
  102. if (delayed_pc) {
  103. ASSERT(is_delay_slot);
  104. pc = *delayed_pc;
  105. delayed_pc = {};
  106. }
  107. switch (opcode.operation) {
  108. case Macro::Operation::ALU: {
  109. u32 result = GetALUResult(opcode.alu_operation, GetRegister(opcode.src_a),
  110. GetRegister(opcode.src_b));
  111. ProcessResult(opcode.result_operation, opcode.dst, result);
  112. break;
  113. }
  114. case Macro::Operation::AddImmediate: {
  115. ProcessResult(opcode.result_operation, opcode.dst,
  116. GetRegister(opcode.src_a) + opcode.immediate);
  117. break;
  118. }
  119. case Macro::Operation::ExtractInsert: {
  120. u32 dst = GetRegister(opcode.src_a);
  121. u32 src = GetRegister(opcode.src_b);
  122. src = (src >> opcode.bf_src_bit) & opcode.GetBitfieldMask();
  123. dst &= ~(opcode.GetBitfieldMask() << opcode.bf_dst_bit);
  124. dst |= src << opcode.bf_dst_bit;
  125. ProcessResult(opcode.result_operation, opcode.dst, dst);
  126. break;
  127. }
  128. case Macro::Operation::ExtractShiftLeftImmediate: {
  129. u32 dst = GetRegister(opcode.src_a);
  130. u32 src = GetRegister(opcode.src_b);
  131. u32 result = ((src >> dst) & opcode.GetBitfieldMask()) << opcode.bf_dst_bit;
  132. ProcessResult(opcode.result_operation, opcode.dst, result);
  133. break;
  134. }
  135. case Macro::Operation::ExtractShiftLeftRegister: {
  136. u32 dst = GetRegister(opcode.src_a);
  137. u32 src = GetRegister(opcode.src_b);
  138. u32 result = ((src >> opcode.bf_src_bit) & opcode.GetBitfieldMask()) << dst;
  139. ProcessResult(opcode.result_operation, opcode.dst, result);
  140. break;
  141. }
  142. case Macro::Operation::Read: {
  143. u32 result = Read(GetRegister(opcode.src_a) + opcode.immediate);
  144. ProcessResult(opcode.result_operation, opcode.dst, result);
  145. break;
  146. }
  147. case Macro::Operation::Branch: {
  148. ASSERT_MSG(!is_delay_slot, "Executing a branch in a delay slot is not valid");
  149. u32 value = GetRegister(opcode.src_a);
  150. bool taken = EvaluateBranchCondition(opcode.branch_condition, value);
  151. if (taken) {
  152. // Ignore the delay slot if the branch has the annul bit.
  153. if (opcode.branch_annul) {
  154. pc = base_address + opcode.GetBranchTarget();
  155. return true;
  156. }
  157. delayed_pc = base_address + opcode.GetBranchTarget();
  158. // Execute one more instruction due to the delay slot.
  159. return Step(true);
  160. }
  161. break;
  162. }
  163. default:
  164. UNIMPLEMENTED_MSG("Unimplemented macro operation {}", opcode.operation.Value());
  165. break;
  166. }
  167. // An instruction with the Exit flag will not actually
  168. // cause an exit if it's executed inside a delay slot.
  169. if (opcode.is_exit && !is_delay_slot) {
  170. // Exit has a delay slot, execute the next instruction
  171. Step(true);
  172. return false;
  173. }
  174. return true;
  175. }
  176. u32 MacroInterpreterImpl::GetALUResult(Macro::ALUOperation operation, u32 src_a, u32 src_b) {
  177. switch (operation) {
  178. case Macro::ALUOperation::Add: {
  179. const u64 result{static_cast<u64>(src_a) + src_b};
  180. carry_flag = result > 0xffffffff;
  181. return static_cast<u32>(result);
  182. }
  183. case Macro::ALUOperation::AddWithCarry: {
  184. const u64 result{static_cast<u64>(src_a) + src_b + (carry_flag ? 1ULL : 0ULL)};
  185. carry_flag = result > 0xffffffff;
  186. return static_cast<u32>(result);
  187. }
  188. case Macro::ALUOperation::Subtract: {
  189. const u64 result{static_cast<u64>(src_a) - src_b};
  190. carry_flag = result < 0x100000000;
  191. return static_cast<u32>(result);
  192. }
  193. case Macro::ALUOperation::SubtractWithBorrow: {
  194. const u64 result{static_cast<u64>(src_a) - src_b - (carry_flag ? 0ULL : 1ULL)};
  195. carry_flag = result < 0x100000000;
  196. return static_cast<u32>(result);
  197. }
  198. case Macro::ALUOperation::Xor:
  199. return src_a ^ src_b;
  200. case Macro::ALUOperation::Or:
  201. return src_a | src_b;
  202. case Macro::ALUOperation::And:
  203. return src_a & src_b;
  204. case Macro::ALUOperation::AndNot:
  205. return src_a & ~src_b;
  206. case Macro::ALUOperation::Nand:
  207. return ~(src_a & src_b);
  208. default:
  209. UNIMPLEMENTED_MSG("Unimplemented ALU operation {}", operation);
  210. return 0;
  211. }
  212. }
  213. void MacroInterpreterImpl::ProcessResult(Macro::ResultOperation operation, u32 reg, u32 result) {
  214. switch (operation) {
  215. case Macro::ResultOperation::IgnoreAndFetch:
  216. // Fetch parameter and ignore result.
  217. SetRegister(reg, FetchParameter());
  218. break;
  219. case Macro::ResultOperation::Move:
  220. // Move result.
  221. SetRegister(reg, result);
  222. break;
  223. case Macro::ResultOperation::MoveAndSetMethod:
  224. // Move result and use as Method Address.
  225. SetRegister(reg, result);
  226. SetMethodAddress(result);
  227. break;
  228. case Macro::ResultOperation::FetchAndSend:
  229. // Fetch parameter and send result.
  230. SetRegister(reg, FetchParameter());
  231. Send(result);
  232. break;
  233. case Macro::ResultOperation::MoveAndSend:
  234. // Move and send result.
  235. SetRegister(reg, result);
  236. Send(result);
  237. break;
  238. case Macro::ResultOperation::FetchAndSetMethod:
  239. // Fetch parameter and use result as Method Address.
  240. SetRegister(reg, FetchParameter());
  241. SetMethodAddress(result);
  242. break;
  243. case Macro::ResultOperation::MoveAndSetMethodFetchAndSend:
  244. // Move result and use as Method Address, then fetch and send parameter.
  245. SetRegister(reg, result);
  246. SetMethodAddress(result);
  247. Send(FetchParameter());
  248. break;
  249. case Macro::ResultOperation::MoveAndSetMethodSend:
  250. // Move result and use as Method Address, then send bits 12:17 of result.
  251. SetRegister(reg, result);
  252. SetMethodAddress(result);
  253. Send((result >> 12) & 0b111111);
  254. break;
  255. default:
  256. UNIMPLEMENTED_MSG("Unimplemented result operation {}", operation);
  257. break;
  258. }
  259. }
  260. bool MacroInterpreterImpl::EvaluateBranchCondition(Macro::BranchCondition cond, u32 value) const {
  261. switch (cond) {
  262. case Macro::BranchCondition::Zero:
  263. return value == 0;
  264. case Macro::BranchCondition::NotZero:
  265. return value != 0;
  266. }
  267. UNREACHABLE();
  268. }
  269. Macro::Opcode MacroInterpreterImpl::GetOpcode() const {
  270. ASSERT((pc % sizeof(u32)) == 0);
  271. ASSERT(pc < code.size() * sizeof(u32));
  272. return {code[pc / sizeof(u32)]};
  273. }
  274. u32 MacroInterpreterImpl::GetRegister(u32 register_id) const {
  275. return registers.at(register_id);
  276. }
  277. void MacroInterpreterImpl::SetRegister(u32 register_id, u32 value) {
  278. // Register 0 is hardwired as the zero register.
  279. // Ensure no writes to it actually occur.
  280. if (register_id == 0) {
  281. return;
  282. }
  283. registers.at(register_id) = value;
  284. }
  285. void MacroInterpreterImpl::SetMethodAddress(u32 address) {
  286. method_address.raw = address;
  287. }
  288. void MacroInterpreterImpl::Send(u32 value) {
  289. maxwell3d.CallMethod(method_address.address, value, true);
  290. // Increment the method address by the method increment.
  291. method_address.address.Assign(method_address.address.Value() +
  292. method_address.increment.Value());
  293. }
  294. u32 MacroInterpreterImpl::Read(u32 method) const {
  295. return maxwell3d.GetRegisterValue(method);
  296. }
  297. u32 MacroInterpreterImpl::FetchParameter() {
  298. ASSERT(next_parameter_index < num_parameters);
  299. return parameters[next_parameter_index++];
  300. }
  301. } // Anonymous namespace
  302. MacroInterpreter::MacroInterpreter(Engines::Maxwell3D& maxwell3d_)
  303. : MacroEngine{maxwell3d_}, maxwell3d{maxwell3d_} {}
  304. std::unique_ptr<CachedMacro> MacroInterpreter::Compile(const std::vector<u32>& code) {
  305. return std::make_unique<MacroInterpreterImpl>(maxwell3d, code);
  306. }
  307. } // namespace Tegra