python_output.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. /*
  2. * Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. */
  6. #include <array>
  7. #include <algorithm>
  8. #include <sstream>
  9. #include <iomanip>
  10. #include <iostream>
  11. #include "output_format.h"
  12. #include "pio_disassembler.h"
  13. struct python_output : public output_format {
  14. struct factory {
  15. factory() {
  16. output_format::add(new python_output());
  17. }
  18. };
  19. python_output() : output_format("python") {}
  20. std::string get_description() override {
  21. return "Python file suitable for use with MicroPython";
  22. }
  23. void output_symbols(FILE *out, std::string prefix, const std::vector<compiled_source::symbol> &symbols) {
  24. int count = 0;
  25. for (const auto &s : symbols) {
  26. if (!s.is_label) {
  27. fprintf(out, "%s%s = %d\n", prefix.c_str(), s.name.c_str(), s.value);
  28. count++;
  29. }
  30. }
  31. if (count) {
  32. fprintf(out, "\n");
  33. count = 0;
  34. }
  35. for (const auto &s : symbols) {
  36. if (s.is_label) {
  37. fprintf(out, "%soffset_%s = %d\n", prefix.c_str(), s.name.c_str(), s.value);
  38. count++;
  39. }
  40. }
  41. if (count) {
  42. fprintf(out, "\n");
  43. }
  44. }
  45. void header(FILE *out, std::string msg) {
  46. std::string dashes = std::string(msg.length(), '-');
  47. fprintf(out, "# %s #\n", dashes.c_str());
  48. fprintf(out, "# %s #\n", msg.c_str());
  49. fprintf(out, "# %s #\n", dashes.c_str());
  50. fprintf(out, "\n");
  51. }
  52. int output(std::string destination, std::vector<std::string> output_options,
  53. const compiled_source &source) override {
  54. FILE *out = open_single_output(destination);
  55. if (!out) return 1;
  56. header(out, "This file is autogenerated by pioasm; do not edit!");
  57. fprintf(out, "import rp2\n");
  58. fprintf(out, "from machine import Pin");
  59. fprintf(out, "\n");
  60. output_symbols(out, "", source.global_symbols);
  61. for (const auto &program : source.programs) {
  62. header(out, program.name);
  63. std::string prefix = program.name + "_";
  64. output_symbols(out, prefix, program.symbols);
  65. int param_count = 0;
  66. auto write_opt = [&] (std::string name, std::string value) {
  67. if (param_count++) {
  68. fprintf(out, ", ");
  69. }
  70. fprintf(out, "%s=%s", name.c_str(), value.c_str());
  71. };
  72. fprintf(out, "@rp2.asm_pio(");
  73. for(const auto &p : program.lang_opts) {
  74. if (p.first.size() >= name.size() && p.first.compare(0, name.size(), name) == 0) {
  75. for (const auto &p2 : p.second) {
  76. write_opt(p2.first, p2.second);
  77. }
  78. }
  79. }
  80. fprintf(out, ")\n");
  81. fprintf(out, "def %s():\n", program.name.c_str());
  82. std::map<uint, std::string> jmp_labels;
  83. // for now just use numeric labels
  84. for (int i = 0; i < (int)program.instructions.size(); i++) {
  85. const auto &inst = program.instructions[i];
  86. if (!(inst >> 13u)) {
  87. // a jump
  88. uint target = inst &0x1fu;
  89. jmp_labels.insert(std::pair<uint,std::string>(target, std::to_string(target)));
  90. }
  91. }
  92. for (uint i = 0; i < (int)program.instructions.size(); i++) {
  93. const auto &inst = program.instructions[i];
  94. if (i == program.wrap_target) {
  95. fprintf(out, " wrap_target()\n");
  96. }
  97. auto it = jmp_labels.find(i);
  98. if (it != jmp_labels.end()) {
  99. fprintf(out, " label(\"%s\")\n", it->second.c_str());
  100. }
  101. fprintf(out, " %s # %d\n", disassemble(jmp_labels, inst, program.sideset_bits_including_opt.get(), program.sideset_opt).c_str(), i);
  102. if (i == program.wrap) {
  103. fprintf(out, " wrap()\n");
  104. }
  105. }
  106. fprintf(out, "\n");
  107. /*
  108. fprintf(out, "static inline pio_sm_config %sprogram_default_config(uint offset) {\n", prefix.c_str());
  109. fprintf(out, " pio_sm_config c = pio_sm_default_config();\n");
  110. fprintf(out, " sm_config_wrap(&c, offset + %swrap_target, offset + %swrap);\n", prefix.c_str(),
  111. prefix.c_str());
  112. if (program.sideset_bits_including_opt.is_specified()) {
  113. fprintf(out, " sm_config_sideset(&c, %d, %s, %s);\n", program.sideset_bits_including_opt.get(),
  114. program.sideset_opt ? "true" : "false",
  115. program.sideset_pindirs ? "true" : "false");
  116. }
  117. fprintf(out, " return c;\n");
  118. fprintf(out, "}\n");
  119. */
  120. // todo maybe have some code blocks inside or outside here?
  121. for(const auto& o : program.code_blocks) {
  122. fprintf(out, "\n");
  123. if (o.first == name) {
  124. for(const auto &contents : o.second) {
  125. fprintf(out, "%s", contents.c_str());
  126. fprintf(out, "\n");
  127. }
  128. }
  129. }
  130. fprintf(out, "\n");
  131. }
  132. if (out != stdout) { fclose(out); }
  133. return 0;
  134. }
  135. static std::string disassemble(const std::map<uint, std::string>& jmp_labels, uint16_t inst, uint sideset_bits_including_opt, bool sideset_opt) {
  136. std::stringstream ss;
  137. uint major = inst >> 13u;
  138. uint arg1 = ((uint) inst >> 5u) & 0x7u;
  139. uint arg2 = inst & 0x1fu;
  140. std::string op_string;
  141. auto op = [&](const std::string &s) {
  142. op_string = s;
  143. };
  144. auto op_guts = [&](const std::string &s) {
  145. ss << std::left << std::setw(24) << (op_string + "(" + s + ")");
  146. };
  147. bool invalid = false;
  148. switch (major) {
  149. case 0b000: {
  150. static std::array<std::string, 8> conditions{"", "not_x", "x_dec", "not_y", "y_dec", "x_not_y", "pin",
  151. "not_osre"};
  152. op("jmp");
  153. auto it = jmp_labels.find(arg2);
  154. std::string label = "?";
  155. if (it != jmp_labels.end()) {
  156. label = it->second;
  157. }
  158. if (arg1)
  159. op_guts(conditions[arg1] + ", \"" + label +"\"");
  160. else
  161. op_guts("\"" + label + "\"");
  162. break;
  163. }
  164. case 0b001: {
  165. uint source = arg1 & 3u;
  166. std::string guts;
  167. switch (source) {
  168. case 0b00:
  169. guts = "gpio, " + std::to_string(arg2);
  170. break;
  171. case 0b01:
  172. guts = "pin, " + std::to_string(arg2);
  173. break;
  174. case 0b10:
  175. if (arg2 & 0x8u) {
  176. invalid = true;
  177. } else {
  178. guts = "irq, ";
  179. auto irq = std::to_string(arg2 & 7u);
  180. if (arg2 & 0x10u) {
  181. guts += "rel(" + irq + ")";
  182. } else {
  183. guts += irq;
  184. }
  185. }
  186. break;
  187. }
  188. if (!invalid) {
  189. guts = ((arg1 & 4u) ? "1, " : "0, ") + guts;
  190. op("wait");
  191. op_guts(guts);
  192. }
  193. break;
  194. }
  195. case 0b010: {
  196. static std::array<std::string, 8> sources { "pins", "x", "y", "null", "", "status", "isr", "osr"};
  197. std::string source = sources[arg1];
  198. if (source.empty()) {
  199. invalid = true;
  200. } else {
  201. op("in_");
  202. op_guts(source + ", " + std::to_string(arg2 ? arg2 : 32));
  203. }
  204. break;
  205. }
  206. case 0b011: {
  207. static std::array<std::string, 8> dests { "pins", "x", "y", "null", "pindirs", "pc", "isr", "exec"};
  208. op("out");
  209. op_guts(dests[arg1] + ", " + std::to_string(arg2 ? arg2 : 32));
  210. break;
  211. }
  212. case 0b100: {
  213. if (arg2) {
  214. invalid = true;
  215. } else {
  216. std::string guts = "";
  217. if (arg1 & 4u) {
  218. op("pull");
  219. if (arg1 & 2u) guts = "ifempty, ";
  220. } else {
  221. op("push");
  222. if (arg1 & 2u) guts = "iffull, ";
  223. }
  224. guts += ((arg1 & 0x1u) ? "block" : "noblock");
  225. op_guts(guts);
  226. }
  227. break;
  228. }
  229. case 0b101: {
  230. static std::array<std::string, 8> dests { "pins", "x", "y", "", "exec", "pc", "isr", "osr"};
  231. static std::array<std::string, 8> sources { "pins", "x", "y", "null", "", "status", "isr", "osr"};
  232. std::string dest = dests[arg1];
  233. std::string source = sources[arg2 & 7u];
  234. uint operation = arg2 >> 3u;
  235. if (source.empty() || dest.empty() || operation == 3) {
  236. invalid = true;
  237. }
  238. if (dest == source && (arg1 == 1 || arg2 == 2)) {
  239. op("nop");
  240. op_guts("");
  241. } else {
  242. op("mov");
  243. std::string guts = dest + ", ";
  244. if (operation == 1) {
  245. guts += "invert(";
  246. } else if (operation == 2) {
  247. guts += "reverse(";
  248. }
  249. guts += source;
  250. if (operation == 1 || operation == 2) {
  251. guts += ")";
  252. }
  253. op_guts(guts);
  254. }
  255. break;
  256. }
  257. case 0b110: {
  258. if ((arg1 & 0x4u) || (arg2 & 0x8u)) {
  259. invalid = true;
  260. } else {
  261. op("irq");
  262. std::string guts;
  263. if (arg1 & 0x2u) {
  264. guts += "clear, ";
  265. } else if (arg1 & 0x1u) {
  266. guts += "block, ";
  267. }
  268. auto irq = std::to_string(arg2 & 7u);
  269. if (arg2 & 0x10u) {
  270. guts += "rel(" + irq + ")";
  271. } else {
  272. guts += irq;
  273. }
  274. op_guts(guts);
  275. }
  276. break;
  277. }
  278. case 0b111: {
  279. static std::array<std::string, 8> dests{"pins", "x", "y", "", "pindirs", "", "", ""};
  280. std::string dest = dests[arg1];
  281. if (dest.empty()) {
  282. invalid = true;
  283. } else {
  284. op("set");
  285. op_guts(dests[arg1] + ", " + std::to_string(arg2));
  286. }
  287. break;
  288. }
  289. }
  290. if (invalid) {
  291. op("word");
  292. ss << std::hex;
  293. op_guts(std::to_string(inst));
  294. }
  295. uint delay = ((uint) inst >> 8u) & 0x1f;
  296. ss << std::left << std::setw(9);
  297. if (sideset_bits_including_opt && (!sideset_opt || (delay & 0x10u))) {
  298. ss << (".side("+ std::to_string((delay & (sideset_opt ? 0xfu : 0x1fu)) >> (5u - sideset_bits_including_opt))+")");
  299. } else {
  300. ss << "";
  301. }
  302. delay &= ((1u << (5 - sideset_bits_including_opt)) - 1u);
  303. ss << std::left << std::setw(4) << (delay ? ("[" + std::to_string(delay) + "]") : "");
  304. return ss.str();
  305. }
  306. };
  307. static python_output::factory creator;