blob: c30fb0b66a1da59a4aca59514c1eb22236df1257 [file] [log] [blame]
Austin Schuh208337d2022-01-01 14:29:11 -08001/*
2 * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <array>
8#include <sstream>
9#include <iomanip>
10#include "pio_disassembler.h"
11
12extern "C" void disassemble(char *buf, int buf_len, uint16_t inst, uint sideset_bits, bool sideset_opt) {
13 if (buf_len) buf[disassemble(inst, sideset_bits, sideset_opt).copy(buf, buf_len - 1)] = 0;
14}
15
16std::string disassemble(uint16_t inst, uint sideset_bits_including_opt, bool sideset_opt) {
17 std::stringstream ss;
18 uint major = inst >> 13u;
19 uint arg1 = ((uint) inst >> 5u) & 0x7u;
20 uint arg2 = inst & 0x1fu;
21 auto op = [&](const std::string &s) {
22 ss << std::left << std::setw(7) << s;
23 };
24 auto op_guts = [&](const std::string &s) {
25 ss << std::left << std::setw(16) << s;
26 };
27
28 bool invalid = false;
29 switch (major) {
30 case 0b000: {
31 static std::array<std::string, 8> conditions{"", "!x, ", "x--, ", "!y, ", "y--, ", "x != y, ", "pin, ",
32 "!osre, "};
33 op("jmp");
34 op_guts(conditions[arg1] + std::to_string(arg2));
35 break;
36 }
37 case 0b001: {
38 uint source = arg1 & 3u;
39 std::string guts;
40 switch (source) {
41 case 0b00:
42 guts = "gpio, " + std::to_string(arg2);
43 break;
44 case 0b01:
45 guts = "pin, " + std::to_string(arg2);
46 break;
47 case 0b10:
48 if (arg2 & 0x8u) {
49 invalid = true;
50 } else {
51 guts = "irq, " + std::to_string(arg2 & 7u);
52 if (arg2 & 0x10u) {
53 guts += " rel";
54 }
55 }
56 break;
57 }
58 if (!invalid) {
59 guts = ((arg1 & 4u) ? "1 " : "0 ") + guts;
60 op("wait");
61 op_guts(guts);
62 }
63 break;
64 }
65 case 0b010: {
66 static std::array<std::string, 8> sources { "pins", "x", "y", "null", "", "status", "isr", "osr"};
67 std::string source = sources[arg1];
68 if (source.empty()) {
69 invalid = true;
70 } else {
71 op("in");
72 op_guts(source + ", " + std::to_string(arg2 ? arg2 : 32));
73 }
74 break;
75 }
76 case 0b011: {
77 static std::array<std::string, 8> dests { "pins", "x", "y", "null", "pindirs", "pc", "isr", "exec"};
78 op("out");
79 op_guts(dests[arg1] + ", " + std::to_string(arg2 ? arg2 : 32));
80 break;
81 }
82 case 0b100: {
83 if (arg2) {
84 invalid = true;
85 } else {
86 std::string guts = "";
87 if (arg1 & 4u) {
88 op("pull");
89 if (arg1 & 2u) guts = "ifempty ";
90 } else {
91 op("push");
92 if (arg1 & 2u) guts = "iffull ";
93 }
94 guts += (arg1 & 0x1u) ? "block" : "noblock";
95 op_guts(guts);
96 }
97 break;
98 }
99 case 0b101: {
100 static std::array<std::string, 8> dests { "pins", "x", "y", "", "exec", "pc", "isr", "osr"};
101 static std::array<std::string, 8> sources { "pins", "x", "y", "null", "", "status", "isr", "osr"};
102 std::string dest = dests[arg1];
103 std::string source = sources[arg2 & 7u];
104 uint operation = arg2 >> 3u;
105 if (source.empty() || dest.empty() || operation == 3) {
106 invalid = true;
107 }
108 if (dest == source && !operation && (arg1 == 1 || arg2 == 2)) {
109 op("nop");
110 op_guts("");
111 } else {
112 op("mov");
113 std::string guts = dest + ", ";
114 if (operation == 1) {
115 guts += "!";
116 } else if (operation == 2) {
117 guts += "::";
118 }
119 guts += source;
120 op_guts(guts);
121 }
122 break;
123 }
124 case 0b110: {
125 if ((arg1 & 0x4u) || (arg2 & 0x8u)) {
126 invalid = true;
127 } else {
128 op("irq");
129 std::string guts;
130 if (arg1 & 0x2u) {
131 guts += "clear ";
132 } else if (arg1 & 0x1u) {
133 guts += "wait ";
134 } else {
135 guts += "nowait ";
136 }
137 guts += std::to_string(arg2 & 7u);
138 if (arg2 & 0x10u) {
139 guts += " rel";
140 }
141 op_guts(guts);
142 }
143 break;
144 }
145 case 0b111: {
146 static std::array<std::string, 8> dests{"pins", "x", "y", "", "pindirs", "", "", ""};
147 std::string dest = dests[arg1];
148 if (dest.empty()) {
149 invalid = true;
150 } else {
151 op("set");
152 op_guts(dests[arg1] + ", " + std::to_string(arg2));
153 }
154 break;
155 }
156 }
157 if (invalid) {
158 return "reserved";
159 }
160 uint delay = ((uint) inst >> 8u) & 0x1f;
161 ss << std::left << std::setw(7);
162 if (sideset_bits_including_opt && (!sideset_opt || (delay & 0x10u))) {
163 ss << ("side "+ std::to_string((delay & (sideset_opt ? 0xfu : 0x1fu)) >> (5u - sideset_bits_including_opt)));
164 } else {
165 ss << "";
166 }
167 delay &= ((1u << (5 - sideset_bits_including_opt)) - 1u);
168 ss << std::left << std::setw(4) << (delay ? ("[" + std::to_string(delay) + "]") : "");
169 return ss.str();
170}
171