FieldMathInstruction.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. /*
  2. * V-Gears
  3. * Copyright (C) 2022 V-Gears Team
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include <iostream>
  19. #include <sstream>
  20. #include <boost/format.hpp>
  21. #include "decompiler/field/instruction/FieldMathInstruction.h"
  22. #include "decompiler/field/FieldEngine.h"
  23. #include "decompiler/field/FieldCodeGenerator.h"
  24. #include "decompiler/field/FieldDisassembler.h"
  25. void FieldMathInstruction::ProcessInst(
  26. Function& func, ValueStack&, Engine* engine, CodeGenerator *code_gen
  27. ){
  28. FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
  29. FunctionMetaData md(func.metadata);
  30. //std::cout << "Math opcode: " << opcode_ << "\n";
  31. switch (opcode_){
  32. case OPCODES::PLUS_: ProcessSaturatedPLUS(code_gen); break;
  33. case OPCODES::PLUS2_: ProcessSaturatedPLUS2(code_gen); break;
  34. case OPCODES::MINUS_: ProcessSaturatedMINUS(code_gen); break;
  35. case OPCODES::MINUS2_: ProcessSaturatedMINUS2(code_gen); break;
  36. case OPCODES::INC_: ProcessSaturatedINC(code_gen); break;
  37. case OPCODES::INC2_: ProcessSaturatedINC2(code_gen); break;
  38. case OPCODES::DEC_: ProcessSaturatedDEC(code_gen); break;
  39. case OPCODES::DEC2_: ProcessSaturatedDEC2(code_gen); break;
  40. case OPCODES::RDMSD: ProcessRDMSD(code_gen); break;
  41. case OPCODES::SETBYTE:
  42. case OPCODES::SETWORD:
  43. ProcessSETBYTE_SETWORD(code_gen);
  44. break;
  45. case OPCODES::BITON: ProcessBITON(code_gen); break;
  46. case OPCODES::BITOFF: ProcessBITOFF(code_gen); break;
  47. case OPCODES::BITXOR: code_gen->WriteTodo(md.GetEntityName(), "BITXOR"); break;
  48. case OPCODES::PLUS:
  49. case OPCODES::PLUS2:
  50. ProcessPLUSx_MINUSx(code_gen, "+");
  51. break;
  52. case OPCODES::MINUS:
  53. case OPCODES::MINUS2:
  54. ProcessPLUSx_MINUSx(code_gen, "-");
  55. break;
  56. case OPCODES::MUL: code_gen->WriteTodo(md.GetEntityName(), "MUL"); break;
  57. case OPCODES::MUL2: code_gen->WriteTodo(md.GetEntityName(), "MUL2"); break;
  58. case OPCODES::DIV: code_gen->WriteTodo(md.GetEntityName(), "DIV"); break;
  59. case OPCODES::DIV2: code_gen->WriteTodo(md.GetEntityName(), "DIV2"); break;
  60. case OPCODES::MOD:
  61. {
  62. const uint32 source_bank = params_[0]->GetUnsigned();
  63. const uint32 sourceaddress__or_value = params_[2]->GetUnsigned();
  64. auto source = FieldCodeGenerator::FormatValueOrVariable(
  65. cg->GetFormatter(), source_bank, sourceaddress__or_value
  66. );
  67. const uint32 dest_bank = params_[1]->GetUnsigned();
  68. const uint32 destaddress_ = params_[3]->GetUnsigned();
  69. auto dest = FieldCodeGenerator::FormatValueOrVariable(
  70. cg->GetFormatter(), dest_bank, destaddress_
  71. );
  72. code_gen->AddOutputLine(
  73. source + " = " + source + " % " + dest + code_gen->GetLanguage().LineTerminator()
  74. );
  75. }
  76. break;
  77. case OPCODES::MOD2: code_gen->WriteTodo(md.GetEntityName(), "MOD2"); break;
  78. case OPCODES::AND: code_gen->WriteTodo(md.GetEntityName(), "AND"); break;
  79. case OPCODES::AND2: code_gen->WriteTodo(md.GetEntityName(), "AND2"); break;
  80. case OPCODES::OR: code_gen->WriteTodo(md.GetEntityName(), "OR"); break;
  81. case OPCODES::OR2: code_gen->WriteTodo(md.GetEntityName(), "OR2"); break;
  82. case OPCODES::XOR: code_gen->WriteTodo(md.GetEntityName(), "XOR"); break;
  83. case OPCODES::XOR2: code_gen->WriteTodo(md.GetEntityName(), "XOR2"); break;
  84. case OPCODES::INC:
  85. case OPCODES::INC2:
  86. ProcessINCx_DECx(code_gen, "+");
  87. break;
  88. case OPCODES::DEC:
  89. case OPCODES::DEC2:
  90. ProcessINCx_DECx(code_gen, "-");
  91. break;
  92. case OPCODES::RANDOM: ProcessRANDOM(code_gen); break;
  93. case OPCODES::LBYTE: code_gen->WriteTodo(md.GetEntityName(), "LBYTE"); break;
  94. case OPCODES::HBYTE: code_gen->WriteTodo(md.GetEntityName(), "HBYTE"); break;
  95. case OPCODES::TWOBYTE: code_gen->WriteTodo(md.GetEntityName(), "2BYTE"); break;
  96. case OPCODES::SIN: code_gen->WriteTodo(md.GetEntityName(), "SIN"); break;
  97. case OPCODES::COS: code_gen->WriteTodo(md.GetEntityName(), "COS"); break;
  98. default:
  99. code_gen->AddOutputLine(FieldCodeGenerator::FormatInstructionNotImplemented(
  100. md.GetEntityName(), address_, opcode_
  101. ));
  102. }
  103. }
  104. void FieldMathInstruction::ProcessSaturatedPLUS(CodeGenerator* code_gen){
  105. FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
  106. // TODO: Check for assignment to value.
  107. const auto& lhs = FieldCodeGenerator::FormatValueOrVariable(
  108. cg->GetFormatter(), params_[0]->GetUnsigned(), params_[2]->GetUnsigned()
  109. );
  110. const auto& rhs = FieldCodeGenerator::FormatValueOrVariable(
  111. cg->GetFormatter(), params_[1]->GetUnsigned(), params_[3]->GetUnsigned()
  112. );
  113. // TODO: Respect destination bank sizes and negative wrap-around.
  114. code_gen->AddOutputLine((boost::format("%1% = %1% + %2%") % lhs % rhs).str());
  115. code_gen->AddOutputLine((boost::format("--if (%1% > 255); %1% = 255; end") % lhs).str());
  116. }
  117. void FieldMathInstruction::ProcessSaturatedPLUS2(CodeGenerator* code_gen){
  118. FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
  119. // TODO: Check for assignment to value.
  120. const auto& lhs = FieldCodeGenerator::FormatValueOrVariable(
  121. cg->GetFormatter(), params_[0]->GetUnsigned(), params_[2]->GetUnsigned()
  122. );
  123. const auto& rhs = FieldCodeGenerator::FormatValueOrVariable(
  124. cg->GetFormatter(), params_[1]->GetUnsigned(), params_[3]->GetUnsigned()
  125. );
  126. // TODO: Respect destination bank sizes and negative wrap-around.
  127. code_gen->AddOutputLine((boost::format("%1% = %1% + %2%") % lhs % rhs).str());
  128. code_gen->AddOutputLine((boost::format("--if (%1% > 32767); %1% = 32767; end") % lhs).str());
  129. }
  130. void FieldMathInstruction::ProcessSaturatedMINUS(CodeGenerator* code_gen){
  131. FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
  132. // TODO: Check for assignment to value.
  133. const auto& lhs = FieldCodeGenerator::FormatValueOrVariable(
  134. cg->GetFormatter(), params_[0]->GetUnsigned(), params_[2]->GetUnsigned()
  135. );
  136. const auto& rhs = FieldCodeGenerator::FormatValueOrVariable(
  137. cg->GetFormatter(), params_[1]->GetUnsigned(), params_[3]->GetUnsigned()
  138. );
  139. // TODO: Respect destination bank sizes and positive wrap-around.
  140. code_gen->AddOutputLine((boost::format("%1% = %1% - %2%") % lhs % rhs).str());
  141. code_gen->AddOutputLine((boost::format("--if (%1% < 0); %1% = 0; end") % lhs).str());
  142. }
  143. void FieldMathInstruction::ProcessSaturatedMINUS2(CodeGenerator* code_gen){
  144. FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
  145. // TODO: Check for assignment to value.
  146. const auto& lhs = FieldCodeGenerator::FormatValueOrVariable(
  147. cg->GetFormatter(), params_[0]->GetUnsigned(), params_[2]->GetUnsigned()
  148. );
  149. const auto& rhs = FieldCodeGenerator::FormatValueOrVariable(
  150. cg->GetFormatter(), params_[1]->GetUnsigned(), params_[3]->GetUnsigned()
  151. );
  152. // TODO: Respect destination bank sizes and positive wrap-around.
  153. code_gen->AddOutputLine((boost::format("%1% = %1% - %2%") % lhs % rhs).str());
  154. code_gen->AddOutputLine((boost::format("--if (%1% < 0); %1% = 0; end") % lhs).str());
  155. }
  156. void FieldMathInstruction::ProcessSaturatedINC(CodeGenerator* code_gen){
  157. FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
  158. // TODO: Check for assignment to value.
  159. const auto& dest = FieldCodeGenerator::FormatValueOrVariable(
  160. cg->GetFormatter(), params_[0]->GetUnsigned(), params_[1]->GetUnsigned()
  161. );
  162. // TODO: Respect destination bank sizes and negative wrap-around.
  163. code_gen->AddOutputLine((boost::format("%1% = %1% + 1") % dest).str());
  164. code_gen->AddOutputLine((boost::format("--if (%1% > 255); %1% = 255; end") % dest).str());
  165. }
  166. void FieldMathInstruction::ProcessSaturatedINC2(CodeGenerator* code_gen){
  167. FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
  168. // TODO: Check for assignment to value.
  169. const auto& dest = FieldCodeGenerator::FormatValueOrVariable(
  170. cg->GetFormatter(), params_[0]->GetUnsigned(), params_[1]->GetUnsigned()
  171. );
  172. // TODO: Respect destination bank sizes and negative wrap-around.
  173. code_gen->AddOutputLine((boost::format("%1% = %1% + 1") % dest).str());
  174. code_gen->AddOutputLine((boost::format("--if (%1% > 32767); %1% = 32767; end") % dest).str());
  175. }
  176. void FieldMathInstruction::ProcessSaturatedDEC(CodeGenerator* code_gen){
  177. FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
  178. // TODO: Check for assignment to value.
  179. const auto& dest = FieldCodeGenerator::FormatValueOrVariable(
  180. cg->GetFormatter(), params_[0]->GetUnsigned(), params_[1]->GetUnsigned()
  181. );
  182. // TODO: Respect destination bank sizes and positive wrap-around.
  183. code_gen->AddOutputLine((boost::format("%1% = %1% - 1") % dest).str());
  184. code_gen->AddOutputLine((boost::format("--if (%1% < 0); %1% = 0; end") % dest).str());
  185. }
  186. void FieldMathInstruction::ProcessSaturatedDEC2(CodeGenerator* code_gen){
  187. FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
  188. // TODO: Check for assignment to value.
  189. const auto& dest = FieldCodeGenerator::FormatValueOrVariable(
  190. cg->GetFormatter(), params_[0]->GetUnsigned(), params_[1]->GetUnsigned()
  191. );
  192. // TODO: Respect destination bank sizes and positive wrap-around.
  193. code_gen->AddOutputLine((boost::format("%1% = %1% - 1") % dest).str());
  194. code_gen->AddOutputLine((boost::format("--if (%1% < 0); %1% = 0; end") % dest).str());
  195. }
  196. void FieldMathInstruction::ProcessRDMSD(CodeGenerator* code_gen){
  197. // TODO: we don't have os.time...
  198. // TODO: RNG emulation?
  199. code_gen->AddOutputLine("math.randomseed(os.time())");
  200. }
  201. void FieldMathInstruction::ProcessSETBYTE_SETWORD(CodeGenerator* code_gen){
  202. FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
  203. // TODO: Check for assignment to value.
  204. const auto& destination = FieldCodeGenerator::FormatValueOrVariable(
  205. cg->GetFormatter(), params_[0]->GetUnsigned(), params_[2]->GetUnsigned()
  206. );
  207. const auto& source = FieldCodeGenerator::FormatValueOrVariable(
  208. cg->GetFormatter(), params_[1]->GetUnsigned(), params_[3]->GetUnsigned()
  209. );
  210. // TODO: respect destination bank sizes (16-bit writes only affect low byte)
  211. code_gen->AddOutputLine((boost::format("%1% = %2%") % destination % source).str());
  212. }
  213. void FieldMathInstruction::ProcessBITON(CodeGenerator* code_gen){
  214. code_gen->AddOutputLine((boost::format("set_bank_bit(%1%, %2%, %3%, 1)")
  215. % params_[0]->GetUnsigned() % params_[2]->GetUnsigned() % params_[3]->GetUnsigned()
  216. ).str());
  217. }
  218. void FieldMathInstruction::ProcessBITOFF(CodeGenerator* code_gen){
  219. code_gen->AddOutputLine((boost::format("set_bank_bit(%1%, %2%, %3%, 0)")
  220. % params_[0]->GetUnsigned() % params_[2]->GetUnsigned() % params_[3]->GetUnsigned()
  221. ).str());
  222. }
  223. void FieldMathInstruction::ProcessPLUSx_MINUSx(CodeGenerator* code_gen, const std::string& op){
  224. FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
  225. // TODO: Check for assignment to value.
  226. const auto& lhs = FieldCodeGenerator::FormatValueOrVariable(
  227. cg->GetFormatter(), params_[0]->GetUnsigned(), params_[2]->GetUnsigned()
  228. );
  229. const auto& rhs = FieldCodeGenerator::FormatValueOrVariable(
  230. cg->GetFormatter(), params_[1]->GetUnsigned(), params_[3]->GetUnsigned()
  231. );
  232. // TODO: repect destination bank sizes and wraparound
  233. code_gen->AddOutputLine((boost::format("%1% = %1% %2% %3%") % lhs % op % rhs).str());
  234. }
  235. void FieldMathInstruction::ProcessINCx_DECx(CodeGenerator* code_gen, const std::string& op){
  236. FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
  237. // TODO: Check for assignment to value.
  238. const auto& destination = FieldCodeGenerator::FormatValueOrVariable(
  239. cg->GetFormatter(), params_[0]->GetUnsigned(), params_[1]->GetUnsigned()
  240. );
  241. // TODO: repect destination bank sizes and wraparound
  242. code_gen->AddOutputLine((boost::format("%1% = %1% %2% 1") % destination % op).str());
  243. }
  244. void FieldMathInstruction::ProcessRANDOM(CodeGenerator* code_gen){
  245. FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
  246. // TODO: Check for assignment to value.
  247. const auto& destination = FieldCodeGenerator::FormatValueOrVariable(
  248. cg->GetFormatter(), params_[0]->GetUnsigned(), params_[1]->GetUnsigned()
  249. );
  250. // TODO: Respect destination bank sizes (16-bit writes only affect low byte).
  251. // TODO: RNG emulation?
  252. code_gen->AddOutputLine((boost::format("%1% = math.random(0, 255)") % destination).str());
  253. }