mirror of
https://github.com/raspberrypi/pico-sdk.git
synced 2025-04-24 18:02:34 +00:00
199 lines
6.8 KiB
C++
199 lines
6.8 KiB
C++
/*
|
|
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
#include <array>
|
|
#include <sstream>
|
|
#include <iomanip>
|
|
#include "pio_disassembler.h"
|
|
|
|
extern "C" void disassemble(char *buf, int buf_len, uint inst, uint sideset_bits, bool sideset_opt) {
|
|
if (buf_len) buf[disassemble(inst, sideset_bits, sideset_opt).copy(buf, buf_len - 1)] = 0;
|
|
}
|
|
|
|
std::string disassemble(uint inst, uint sideset_bits_including_opt, bool sideset_opt) {
|
|
std::stringstream ss;
|
|
uint major = (inst >> 13u) & 0x7;
|
|
uint arg1 = ((uint) inst >> 5u) & 0x7u;
|
|
uint arg2 = (inst & 0x1fu) | ((inst & 0x10000) >> 11);
|
|
auto op = [&](const std::string &s) {
|
|
ss << std::left << std::setw(7) << s;
|
|
};
|
|
auto op_guts = [&](const std::string &s) {
|
|
ss << std::left << std::setw(16) << s;
|
|
};
|
|
|
|
bool invalid = false;
|
|
switch (major) {
|
|
case 0b000: {
|
|
static std::array<std::string, 8> conditions{"", "!x, ", "x--, ", "!y, ", "y--, ", "x != y, ", "pin, ",
|
|
"!osre, "};
|
|
op("jmp");
|
|
op_guts(conditions[arg1] + std::to_string(arg2));
|
|
break;
|
|
}
|
|
case 0b001: {
|
|
uint source = arg1 & 3u;
|
|
std::string guts;
|
|
switch (source) {
|
|
case 0b00:
|
|
guts = "gpio, " + std::to_string(arg2);
|
|
break;
|
|
case 0b01:
|
|
guts = "pin, " + std::to_string(arg2);
|
|
break;
|
|
case 0b10:
|
|
guts = "irq";
|
|
if (arg2 & 0x08) {
|
|
guts += arg2 & 0x10 ? " next" : " prev";
|
|
}
|
|
guts += ", " + std::to_string(arg2 & 7u);
|
|
if (0x10 == (arg2 & 0x18)) guts += " rel";
|
|
break;
|
|
case 0b11:
|
|
if (arg2 & 0x1cu) {
|
|
invalid = true;
|
|
} else if (arg2) {
|
|
guts = "jmppin " + std::to_string(arg2 & 3u);
|
|
}
|
|
break;
|
|
}
|
|
if (!invalid) {
|
|
guts = ((arg1 & 4u) ? "1 " : "0 ") + guts;
|
|
op("wait");
|
|
op_guts(guts);
|
|
}
|
|
break;
|
|
}
|
|
case 0b010: {
|
|
static std::array<std::string, 8> sources { "pins", "x", "y", "null", "", "status", "isr", "osr"};
|
|
std::string source = sources[arg1];
|
|
if (source.empty()) {
|
|
invalid = true;
|
|
} else {
|
|
op("in");
|
|
op_guts(source + ", " + std::to_string(arg2 ? arg2 : 32));
|
|
}
|
|
break;
|
|
}
|
|
case 0b011: {
|
|
static std::array<std::string, 8> dests { "pins", "x", "y", "null", "pindirs", "pc", "isr", "exec"};
|
|
op("out");
|
|
op_guts(dests[arg1] + ", " + std::to_string(arg2 ? arg2 : 32));
|
|
break;
|
|
}
|
|
case 0b100: {
|
|
if (arg2) {
|
|
if ((arg1 & 3) || !(arg2 & 0x10)) {
|
|
invalid = true;
|
|
} else {
|
|
std::string index;
|
|
if (arg2 & 8) index = "y";
|
|
else index = std::to_string(arg2 & 7);
|
|
std::string guts = "";
|
|
op("mov");
|
|
if (arg1 & 4) {
|
|
guts = "osr, rxfifo[" + index + "]";
|
|
} else {
|
|
guts = "rxfifo[" + index + "], isr";
|
|
}
|
|
op_guts(guts);
|
|
}
|
|
} else {
|
|
std::string guts = "";
|
|
if (arg1 & 4u) {
|
|
op("pull");
|
|
if (arg1 & 2u) guts = "ifempty ";
|
|
} else {
|
|
op("push");
|
|
if (arg1 & 2u) guts = "iffull ";
|
|
}
|
|
guts += (arg1 & 0x1u) ? "block" : "noblock";
|
|
op_guts(guts);
|
|
}
|
|
break;
|
|
}
|
|
case 0b101: {
|
|
static std::array<std::string, 8> dests { "pins", "x", "y", "pindirs", "exec", "pc", "isr", "osr"};
|
|
static std::array<std::string, 8> sources { "pins", "x", "y", "null", "", "status", "isr", "osr"};
|
|
std::string dest = dests[arg1];
|
|
std::string source = sources[arg2 & 7u];
|
|
uint operation = arg2 >> 3u;
|
|
if (source.empty() || dest.empty() || operation == 3) {
|
|
invalid = true;
|
|
}
|
|
if (dest == source && !operation && (arg1 == 1 || arg2 == 2)) {
|
|
op("nop");
|
|
op_guts("");
|
|
} else {
|
|
op("mov");
|
|
std::string guts = dest + ", ";
|
|
if (operation == 1) {
|
|
guts += "!";
|
|
} else if (operation == 2) {
|
|
guts += "::";
|
|
}
|
|
guts += source;
|
|
op_guts(guts);
|
|
}
|
|
break;
|
|
}
|
|
case 0b110: {
|
|
if ((arg1 & 0x4u)) {
|
|
invalid = true;
|
|
} else {
|
|
op("irq");
|
|
std::string guts;
|
|
if (arg1 & 0x2u) {
|
|
guts += "clear ";
|
|
} else if (arg1 & 0x1u) {
|
|
guts += "wait ";
|
|
} else {
|
|
guts += "nowait ";
|
|
}
|
|
guts += std::to_string(arg2 & 7u);
|
|
switch(arg2 & 0x18) {
|
|
case 0x10:
|
|
guts += " rel";
|
|
break;
|
|
case 0x08:
|
|
guts = "prev "+guts;
|
|
break;
|
|
case 0x18:
|
|
guts = "next "+guts;
|
|
break;
|
|
}
|
|
op_guts(guts);
|
|
}
|
|
break;
|
|
}
|
|
case 0b111: {
|
|
static std::array<std::string, 8> dests{"pins", "x", "y", "", "pindirs", "", "", ""};
|
|
std::string dest = dests[arg1];
|
|
if (dest.empty()) {
|
|
invalid = true;
|
|
} else {
|
|
op("set");
|
|
op_guts(dests[arg1] + ", " + std::to_string(arg2));
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if (invalid) {
|
|
return "reserved";
|
|
}
|
|
uint delay = ((uint) inst >> 8u) & 0x1f;
|
|
ss << std::left << std::setw(7);
|
|
if (sideset_bits_including_opt && (!sideset_opt || (delay & 0x10u))) {
|
|
ss << ("side "+ std::to_string((delay & (sideset_opt ? 0xfu : 0x1fu)) >> (5u - sideset_bits_including_opt)));
|
|
} else {
|
|
ss << "";
|
|
}
|
|
delay &= ((1u << (5 - sideset_bits_including_opt)) - 1u);
|
|
ss << std::left << std::setw(4) << (delay ? ("[" + std::to_string(delay) + "]") : "");
|
|
return ss.str();
|
|
}
|
|
|