File: go_output.cpp

package info (click to toggle)
pico-sdk 2.2.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 26,960 kB
  • sloc: ansic: 150,165; asm: 13,474; python: 2,885; cpp: 2,192; yacc: 381; lex: 270; makefile: 33; sh: 15; javascript: 13
file content (131 lines) | stat: -rw-r--r-- 4,664 bytes parent folder | download
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;