-
Notifications
You must be signed in to change notification settings - Fork 0
/
build.zig
150 lines (122 loc) · 4.54 KB
/
build.zig
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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
const std = @import("std");
pub fn build(b: *std.build.Builder) !void {
const mode = b.standardReleaseOptions();
const pico_exe = PicoExe.init(b, "zig-blink", "app/main.zig");
//try pico_exe.addPioSource(.{ .name = "pwm", .file = "pwm.pio" });
const exe = pico_exe.exe;
exe.setBuildMode(mode);
exe.install();
// TODO: Implement uf2 generation and flashing with picotool. End goal would
// be to compile and cache the tools when they are needed.
//const uf2_cmd = b.addSystemCommand(&.{"elf2uf2"});
//uf2_cmd.addArtifactArg(exe);
//uf2_cmd.addArg("zig-out/bin/zig-blink.uf2");
//const uf2 = b.step("uf2", "Build program and convert to uf2");
//uf2.dependOn(&uf2_cmd.step);
//const flash_cmd = b.addSystemCommand(&.{"picotool", "load", "-x", "zig-out/bin/zig-blink.uf2"});
//const flash = b.step("flash", "Build and flash to Pico. This requires picotool, and udev rules to set permissions for Pico devices");
//flash.dependOn(uf2);
//flash.dependOn(&flash_cmd.step);
}
const PioSource = struct {
name: []const u8,
file: []const u8,
};
pub const PicoExe = struct {
exe: *std.build.LibExeObjStep,
pio_step: *std.build.OptionsStep,
pub fn init(
builder: *std.build.Builder,
name: []const u8,
app_src: []const u8
) PicoExe {
const target = std.zig.CrossTarget{
.cpu_arch = .thumb,
.cpu_model = .{ .explicit = &std.Target.arm.cpu.cortex_m0plus },
.os_tag = .freestanding,
.abi = .eabi,
};
// The zig-pico sdk package used by the user application.
const pico = std.build.Pkg{
.name = "pico",
.path = .{ .path = "src/pico.zig" },
};
// The generated bytecode for the PIO peripheral
const pio_step = builder.addOptions();
const pio = std.build.Pkg{
.name = "pio-bytecode",
.path = .{ .generated = &pio_step.generated_file },
};
// The user applcation
const app = std.build.Pkg{
.name = "app",
.path = .{ .path = app_src },
.dependencies = &.{ pico, pio },
};
const exe = builder.addExecutable(name, "src/crt0.zig");
exe.single_threaded = true;
exe.setTarget(target);
exe.setLinkerScriptPath(.{ .path = "simple.ld" });
exe.addPackage(app);
return PicoExe{
.exe = exe,
.pio_step = pio_step,
};
}
pub fn addPioSource(self: PicoExe, source: PioSource) !void {
const program = try pioasm(self.exe.builder.allocator, source.file);
defer self.exe.builder.allocator.free(program);
self.pio_step.addOption([]const u16, source.name, program);
}
pub fn addPioSources(self: PicoExe, sources: []const PioSource) !void {
for (sources) |source| {
try self.addPioSource(source);
}
}
};
// TODO: Add the pioc-sdk tools dir as a dependency and compile and cache the
// pioasm tool and use that instead of a system wide installed verison.
// TODO: See if compilation of the pio files can be done as a step, with the
// result cached if there are no changes.
fn pioasm(alloc: std.mem.Allocator, file: []const u8) ![]u16 {
const child = std.ChildProcess.init(&.{
"pioasm",
"-o",
"hex",
file
}, alloc) catch unreachable;
defer child.deinit();
//child.cwd = exe.builder.build_root;
//child.env_map = self.builder.env_map;
child.stdin_behavior = .Ignore;
child.stdout_behavior = .Pipe;
child.stderr_behavior = .Inherit;
child.spawn() catch |err| {
std.debug.print("Unable to spawn pioasm: {s}\n", .{ @errorName(err) });
return err;
};
var out = std.ArrayList(u16).init(alloc);
const reader = child.stdout.?.reader();
var buf: [5]u8 = undefined;
while (try reader.readUntilDelimiterOrEof(&buf, '\n')) |line| {
const int = try std.fmt.parseInt(u16, line, 16);
try out.append(int);
}
const term = child.wait() catch |err| {
std.debug.print("Unable to spawn pioasm: {s}\n", .{ @errorName(err) });
return err;
};
switch (term) {
.Exited => |code| {
if (code != 0) {
std.debug.print("Pioasm exited with error code {}.\n", .{ code });
return error.PioasmError;
}
},
else => {
std.debug.print("Pioasm terminated unexpectedly..?\n", .{});
return error.UncleanExit;
},
}
return out.toOwnedSlice();
}