tinygo-org / pio

Programmable I/O API for RP2040.
BSD 3-Clause "New" or "Revised" License
19 stars 0 forks source link

pioasm-go dependency #12

Open 0pcom opened 1 month ago

0pcom commented 1 month ago

Changing any .pio code in any example and running go generate will encounter the dependency of a special version of pioasm which is not mentioned in the readme but available at @soypat 's fork of pico-sdk on the pioasm-go branch.

However, there are errors compiling pioasm on that branch. The following code should address those issues.

==> pio_disassembler.cpp <==
/*
 * 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, uint16_t inst, unsigned int sideset_bits, bool sideset_opt) {
    if (buf_len) buf[disassemble(inst, sideset_bits, sideset_opt).copy(buf, buf_len - 1)] = 0;
}

std::string disassemble(uint16_t inst, unsigned int sideset_bits_including_opt, bool sideset_opt) {
    std::stringstream ss;
    unsigned int major = inst >> 13u;
    unsigned int arg1 = ((unsigned int) inst >> 5u) & 0x7u;
    unsigned int arg2 = inst & 0x1fu;
    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: {
            unsigned int 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:
                    if (arg2 & 0x8u) {
                        invalid = true;
                    } else {
                        guts = "irq, " + std::to_string(arg2 & 7u);
                        if (arg2 & 0x10u) {
                            guts += " rel";
                        }
                    }
                    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) {
                invalid = true;
            } 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", "", "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];
            unsigned int 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) || (arg2 & 0x8u)) {
                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);
                if (arg2 & 0x10u) {
                    guts += " rel";
                }
                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";
    }
    unsigned int delay = ((unsigned int) 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();
}

==> pio_disassembler.h <==
/*
 * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#ifndef _PIO_DISASSEMBLER_H
#define _PIO_DISASSEMBLER_H

#ifdef __cplusplus
#include <cstdint>
#include <string>

typedef unsigned int uint;

std::string disassemble(uint16_t inst, uint sideset_bits, bool sideset_opt);
extern "C" void disassemble(char *buf, int buf_len, uint16_t inst, uint sideset_bits, bool sideset_opt);

#else
#include <stdint.h>

void disassemble(char *buf, int buf_len, uint16_t inst, unsigned int sideset_bits, bool sideset_opt);

#endif

#endif

Perhaps a readme in the examples dir could be added to explain this aspect of the library's usage, for those who are not already otherwise familiar with or using the pico-sdk

mpictor commented 2 weeks ago

The PR got merged into the sdk's develop branch: https://github.com/raspberrypi/pico-sdk/pull/1604 ... and a new release was cut 3 weeks ago - probably right about the time you opened this issue.

That said, I'm not (yet) sure how to get pioasm to compile without installing arm compilers, breaking a leg, etc etc.

I thought I'd be able to

mkdir build; cd build
cmake .. -DPICO_PLATFORM=host
make

...but the resulting makefile does nothing but build some pico stdlib tests.

soypat commented 1 week ago

To build pioasm tool I've found you can do the following (starting from scratch, fresh directory, no environment variables only make and cmake required):

git clone git@github.com:raspberrypi/pico-sdk.git
cd pico-sdk/tools/pioasm
cmake . && make

Should output something like:

[  8%] Building CXX object CMakeFiles/pioasm.dir/main.cpp.o
[ 16%] Building CXX object CMakeFiles/pioasm.dir/pio_assembler.cpp.o
[ 25%] Building CXX object CMakeFiles/pioasm.dir/pio_disassembler.cpp.o
[ 33%] Building CXX object CMakeFiles/pioasm.dir/gen/lexer.cpp.o
[ 41%] Building CXX object CMakeFiles/pioasm.dir/gen/parser.cpp.o
[ 50%] Building CXX object CMakeFiles/pioasm.dir/c_sdk_output.cpp.o
[ 58%] Building CXX object CMakeFiles/pioasm.dir/python_output.cpp.o
[ 66%] Building CXX object CMakeFiles/pioasm.dir/hex_output.cpp.o
[ 75%] Building CXX object CMakeFiles/pioasm.dir/json_output.cpp.o
[ 83%] Building CXX object CMakeFiles/pioasm.dir/ada_output.cpp.o
[ 91%] Building CXX object CMakeFiles/pioasm.dir/go_output.cpp.o
[100%] Linking CXX executable pioasm
[100%] Built target pioasm

and finally test your new binary by running help: ./pioasm --help

./pioasm --help
usage: pioasm <options> <input> (<output>)

Assemble file of PIO program(s) for use in applications.
   <input>             the input filename
   <output>            the output filename (or filename prefix if the output format produces multiple outputs).
                       if not specified, a single output will be written to stdout

options:
  -o <output_format>   select output_format (default 'c-sdk'); available options are:
                           c-sdk
                               C header suitable for use with the Raspberry Pi Pico SDK
                           python
                               Python file suitable for use with MicroPython
                           hex
                               Raw hex output (only valid for single program inputs)
                           json
                               Machine-formatted output for integrating with external tools
                           ada
                               Ada specification
                           go
                               Go file suitable for use with TinyGo. See https://github.com/tinygo-org/pio.
  -p <output_param>    add a parameter to be passed to the output format generator
  -v <version>         specify the default PIO version (0 or 1)
  -?, --help           print this help and exit
mpictor commented 1 week ago
cd pico-sdk/tools/pioasm
cmake . && make

Too easy :stuck_out_tongue_closed_eyes:

thanks!