1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
|
/*
* Copyright (c) 2024 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*
* Contributed by the TinyGo authors.
*
* Go generated by this assembler is compatible with TinyGo.
*
* https://tinygo.org
* https://github.com/tinygo-org/tinygo
* https://github.com/tinygo-org/pio
*/
#include <algorithm>
#include <iostream>
#include <sstream>
#include "output_format.h"
#include "pio_disassembler.h"
#include "version.h"
struct go_output : public output_format {
struct factory {
factory() {
output_format::add(new go_output());
}
};
go_output() : output_format("go") {}
std::string get_description() override {
return "Go file suitable for use with TinyGo. See https://github.com/tinygo-org/pio.";
}
void output_symbols(FILE *out, std::string prefix, const std::vector<compiled_source::symbol> &symbols) {
int count = 0;
for (const auto &s : symbols) {
if (!s.is_label) {
fprintf(out, "const %s%s = %d\n", prefix.c_str(), s.name.c_str(), s.value);
count++;
}
}
if (count) {
fprintf(out, "\n");
count = 0;
}
for (const auto &s : symbols) {
if (s.is_label) {
fprintf(out, "const %soffset_%s = %d\n", prefix.c_str(), s.name.c_str(), s.value);
count++;
}
}
if (count) {
fprintf(out, "\n");
}
}
void header(FILE *out, std::string msg) {
fprintf(out, "// %s\n\n", msg.c_str());
}
int output(std::string destination, std::vector<std::string> output_options,
const compiled_source &source) override {
FILE *out = open_single_output(destination);
if (!out) return 1;
std::stringstream header_string;
header_string << "This file is autogenerated by pioasm version " << PIOASM_VERSION_STRING << "; do not edit!";
header(out, header_string.str());
// First we give priority to user's code blocks since
// 1. In Go our imports always precede our code.
// 2. We give users the freedom to use their own PIO implementation.
for (const auto &program : source.programs) {
for(const auto& o : program.code_blocks) {
if (o.first == name) {
for(const auto &contents : o.second) {
fprintf(out, "%s", contents.c_str());
}
}
}
}
for (const auto &program : source.programs) {
header(out, program.name);
std::string prefix = program.name;
fprintf(out, "const %sWrapTarget = %d\n", prefix.c_str(), program.wrap_target);
fprintf(out, "const %sWrap = %d\n", prefix.c_str(), program.wrap);
fprintf(out, "\n");
output_symbols(out, prefix, program.symbols);
fprintf(out, "var %sInstructions = []uint16{\n", prefix.c_str());
for (int i = 0; i < (int)program.instructions.size(); i++) {
const auto &inst = program.instructions[i];
if (i == program.wrap_target) {
fprintf(out, "\t\t// .wrap_target\n");
}
fprintf(out, "\t\t0x%04x, // %2d: %s\n", inst, i,
disassemble(inst, program.sideset_bits_including_opt.get(), program.sideset_opt).c_str());
if (i == program.wrap) {
fprintf(out, "\t\t// .wrap\n");
}
}
fprintf(out, "}\n");
fprintf(out, "const %sOrigin = %d\n", prefix.c_str(), program.origin.get());
fprintf(out, "func %sProgramDefaultConfig(offset uint8) pio.StateMachineConfig {\n", prefix.c_str());
fprintf(out, "\tcfg := pio.DefaultStateMachineConfig()\n");
fprintf(out, "\tcfg.SetWrap(offset+%sWrapTarget, offset+%sWrap)\n", prefix.c_str(),
prefix.c_str());
if (program.sideset_bits_including_opt.is_specified()) {
fprintf(out, "\tcfg.SetSidesetParams(%d, %s, %s)\n", program.sideset_bits_including_opt.get(),
program.sideset_opt ? "true" : "false",
program.sideset_pindirs ? "true" : "false");
}
fprintf(out, "\treturn cfg;\n");
fprintf(out, "}\n\n");
}
output_symbols(out, "", source.global_symbols);
if (out != stdout) { fclose(out); }
return 0;
}
};
static go_output::factory creator;
|