Skip to content

Commit

Permalink
Build carts for WASM and native targets (#31)
Browse files Browse the repository at this point in the history
* wip

* add linkerscript for bootloaded applications

* wasm4 -> cart
  • Loading branch information
mattnite authored Apr 27, 2024
1 parent 4c45680 commit 1dfa26c
Show file tree
Hide file tree
Showing 22 changed files with 22,186 additions and 542 deletions.
190 changes: 98 additions & 92 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -10,52 +10,71 @@ pub const py_badge: MicroZig.Target = .{
.hal = null,
};

pub const sycl_badge_2024 = MicroZig.Target{
pub const sycl_badge = MicroZig.Target{
.preferred_format = .elf,
.chip = atsam.chips.atsamd51j19.chip,
.hal = .{
.root_source_file = .{ .cwd_relative = "src/hal.zig" },
},
.board = .{
.name = "SYCL Badge 2024",
.name = "SYCL Badge Rev A",
.root_source_file = .{ .cwd_relative = "src/board.zig" },
},
.linker_script = .{ .cwd_relative = "src/badge/samd51j19a_self.ld" },
};

pub fn build(b: *Build) void {
const mz = MicroZig.init(b, .{});
const optimize = b.standardOptimizeOption(.{});

const wasm_target = b.resolveTargetQuery(.{
.cpu_arch = .wasm32,
.os_tag = .freestanding,
const ws_dep = b.dependency("ws", .{});
const mime_dep = b.dependency("mime", .{});

_ = b.addModule("cart-api", .{ .root_source_file = .{ .path = "src/cart/api.zig" } });

const watch = b.addExecutable(.{
.name = "watch",
.root_source_file = .{ .path = "src/watch/main.zig" },
.target = b.host,
.optimize = optimize,
});
const optimize = b.standardOptimizeOption(.{});
watch.root_module.addImport("ws", ws_dep.module("websocket"));
watch.root_module.addImport("mime", mime_dep.module("mime"));

_ = b.addModule("wasm4", .{ .root_source_file = .{ .path = "src/wasm4.zig" } });
if (b.host.result.os.tag == .macos) {
watch.linkFramework("CoreFoundation");
watch.linkFramework("CoreServices");
}

var dep: std.Build.Dependency = .{ .builder = b };
_ = add_cart(&dep, b, .{
.name = "sample",
.target = wasm_target,
const feature_test_cart = add_cart(&dep, b, .{
.name = "feature_test",
.optimize = .ReleaseSmall,
.root_source_file = .{ .path = "samples/feature_test.zig" },
});
feature_test_cart.install(b);

const zeroman_cart = add_cart(&dep, b, .{
.name = "zeroman",
.target = wasm_target,
.optimize = .ReleaseSmall,
.root_source_file = .{ .path = "samples/zeroman/main.zig" },
});
add_zeroman_assets_step(b, zeroman_cart);
zeroman_cart.install(b);
//
// TODO: parameterize:
const watch_run = b.addRunArtifact(watch);
watch_run.addArg("serve");
watch_run.addArtifactArg(feature_test_cart.wasm);
watch_run.addArgs(&.{ "--zig-out-bin-dir", "zig-out/bin" });

const watch_step = b.step("watch", "");
watch_step.dependOn(&zeroman_cart.watch_run_cmd.step);
watch_step.dependOn(&watch_run.step);

const badge = mz.add_firmware(b, .{
.name = "badge",
.target = sycl_badge_2024,
.optimize = optimize,
.target = sycl_badge,
.optimize = .ReleaseSmall,
.root_source_file = .{ .path = "src/badge.zig" },
});
mz.install_firmware(b, badge, .{});
Expand All @@ -66,19 +85,23 @@ pub fn build(b: *Build) void {
"usb_cdc",
"usb_storage",
"buttons",
"lcd",
//"lcd",
"audio",
"light_sensor",
"neopixels",
"qspi",
"qa",
}) |name| {
const mvp = mz.add_firmware(b, .{
.name = std.fmt.comptimePrint("badge.demo.{s}", .{name}),
.target = sycl_badge_2024,
.target = sycl_badge,
.optimize = optimize,
.root_source_file = .{ .path = std.fmt.comptimePrint("src/badge/demos/{s}.zig", .{name}) },
});
mz.install_firmware(b, mvp, .{});
mz.install_firmware(b, mvp, .{
.format = .{ .uf2 = .SAMD51 },
});
}

const font_export_step = b.step("generate-font.ts", "convert src/font.zig to simulator/src/font.ts");
Expand All @@ -101,17 +124,22 @@ pub fn build(b: *Build) void {
}

pub const Cart = struct {
// mz: *MicroZig,
// fw: *MicroZig.Firmware,
fw: *MicroZig.Firmware,
wasm: *Build.Step.Compile,
mz: *MicroZig,
cart_lib: *Build.Step.Compile,

options: CartOptions,
lib: *std.Build.Step.Compile,
watch_run_cmd: *std.Build.Step.Run,
//watch_run_cmd: *std.Build.Step.Run,

pub fn install(c: *const Cart, b: *Build) void {
c.mz.install_firmware(b, c.fw, .{ .format = .{ .uf2 = .SAMD51 } });
b.installArtifact(c.wasm);
}
};

pub const CartOptions = struct {
name: []const u8,
target: std.Build.ResolvedTarget,
optimize: std.builtin.OptimizeMode,
root_source_file: Build.LazyPath,
};
Expand All @@ -121,91 +149,69 @@ pub fn add_cart(
b: *Build,
options: CartOptions,
) *Cart {
const lib = b.addExecutable(.{
.name = "cart",
const wasm_target = b.resolveTargetQuery(.{
.cpu_arch = .wasm32,
.os_tag = .freestanding,
});

const wasm = b.addExecutable(.{
.name = options.name,
.root_source_file = options.root_source_file,
.target = options.target,
.target = wasm_target,
.optimize = options.optimize,
});
b.installArtifact(lib);

lib.entry = .disabled;
lib.import_memory = true;
lib.initial_memory = 2 * 65536;
lib.max_memory = 2 * 65536;
lib.stack_size = 14752;
lib.global_base = 160 * 128 * 2 + 0x1e;
wasm.entry = .disabled;
wasm.import_memory = true;
wasm.initial_memory = 2 * 65536;
wasm.max_memory = 2 * 65536;
wasm.stack_size = 14752;
wasm.global_base = 160 * 128 * 2 + 0x1e;

lib.rdynamic = true;
wasm.rdynamic = true;
wasm.root_module.addImport("cart-api", d.module("cart-api"));

lib.root_module.addImport("wasm4", d.module("wasm4"));
const sycl_badge_target =
b.resolveTargetQuery(sycl_badge.chip.cpu.target);

const host_target = b.resolveTargetQuery(.{});
const watch = d.builder.addExecutable(.{
.name = "watch",
.root_source_file = .{ .path = "src/watch/main.zig" },
.target = host_target,
const cart_lib = b.addStaticLibrary(.{
.name = "cart",
.root_source_file = options.root_source_file,
.target = sycl_badge_target,
.optimize = options.optimize,
.link_libc = false,
.single_threaded = true,
.use_llvm = true,
.use_lld = true,
});
watch.root_module.addImport("ws", d.builder.dependency("ws", .{}).module("websocket"));
watch.root_module.addImport("mime", d.builder.dependency("mime", .{}).module("mime"));
cart_lib.root_module.addImport("cart-api", d.module("cart-api"));
cart_lib.linker_script = .{ .path = "src/cart.ld" };

if (host_target.result.os.tag == .macos) {
watch.linkFramework("CoreFoundation");
watch.linkFramework("CoreServices");
}
const fw_options = b.addOptions();
fw_options.addOption(bool, "have_cart", true);

const watch_run_cmd = b.addRunArtifact(watch);
watch_run_cmd.step.dependOn(b.getInstallStep());
const mz = MicroZig.init(d.builder, .{});

watch_run_cmd.addArgs(&.{
"serve",
b.graph.zig_exe,
"--zig-out-bin-dir",
b.pathJoin(&.{ b.install_path, "bin" }),
"--input-dir",
options.root_source_file.dirname().getPath(b),
const fw = mz.add_firmware(d.builder, .{
.name = options.name,
.target = sycl_badge,
.optimize = options.optimize,
.root_source_file = .{ .path = "src/main.zig" },
.linker_script = .{ .path = "src/cart.ld" },
});
fw.artifact.linkLibrary(cart_lib);
fw.artifact.step.dependOn(&fw_options.step);
fw.modules.app.addOptions("options", fw_options);

const cart: *Cart = b.allocator.create(Cart) catch @panic("out of memory");
const cart: *Cart = b.allocator.create(Cart) catch @panic("OOM");
cart.* = .{
.mz = mz,
.wasm = wasm,
.fw = fw,
.cart_lib = cart_lib,
.options = options,
.lib = lib,
.watch_run_cmd = watch_run_cmd,
};
return cart;

// const cart_lib = b.addStaticLibrary(.{
// .name = "cart",
// .root_source_file = options.source_file,
// .target = py_badge.chip.cpu.getDescriptor().target,
// .optimize = options.optimize,
// .link_libc = false,
// .single_threaded = true,
// .use_llvm = true,
// .use_lld = true,
// });
// cart_lib.addModule("wasm4", d.module("wasm4"));

// const fw_options = b.addOptions();
// fw_options.addOption(bool, "have_cart", true);

// const mz = MicroZig.init(d.builder, "microzig");

// const fw = mz.addFirmware(d.builder, .{
// .name = options.name,
// .target = py_badge,
// .optimize = .Debug, // TODO
// .source_file = .{ .path = "src/main.zig" },
// .linker_script = .{ .source_file = .{ .path = "src/cart.ld" } },
// });
// fw.artifact.linkLibrary(cart_lib);
// fw.artifact.step.dependOn(&fw_options.step);
// fw.modules.app.dependencies.put("options", fw_options.createModule()) catch @panic("out of memory");

// const cart: *Cart = b.allocator.create(Cart) catch @panic("out of memory");
// cart.* = .{ .mz = mz, .fw = fw };
// return cart;
}

pub fn install_cart(b: *Build, cart: *Cart) void {
Expand Down Expand Up @@ -236,14 +242,14 @@ fn add_zeroman_assets_step(b: *Build, cart: *Cart) void {

const gfx_mod = b.addModule("gfx", .{
.root_source_file = gfx_zig,
.target = cart.options.target,
.optimize = cart.options.optimize,
});
var dep: std.Build.Dependency = .{ .builder = b };
gfx_mod.addImport("wasm4", dep.module("wasm4"));
gfx_mod.addImport("cart-api", dep.module("cart-api"));

cart.lib.step.dependOn(&gen_gfx.step);
cart.lib.root_module.addImport("gfx", gfx_mod);
cart.wasm.step.dependOn(&gen_gfx.step);
cart.wasm.root_module.addImport("gfx", gfx_mod);
cart.cart_lib.root_module.addImport("gfx", gfx_mod);
}

const GfxAsset = struct { path: []const u8, bits: u4, transparency: bool };
Expand Down
83 changes: 83 additions & 0 deletions build/image_to_splash.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
const std = @import("std");
const img = @import("img");

const Arguments = struct {
output_path: ?[]const u8 = null,
};

pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();

var arena = std.heap.ArenaAllocator.init(gpa.allocator());
defer arena.deinit();

const allocator = arena.allocator();
const args = try std.process.argsAlloc(allocator);
defer std.process.argsFree(allocator, args);

var input_file_arg: ?[]const u8 = null;
var output_file_arg: ?[]const u8 = null;

{
var i: u32 = 1;
while (i < args.len) : (i += 1) {
if (std.mem.eql(u8, args[i], "-o")) {
if (i + 1 >= args.len)
return error.MissingOutputFileArg;

output_file_arg = args[i + 1];
i += 1;
} else {
input_file_arg = args[i];
}
}
}

const input_file_path = input_file_arg orelse unreachable;
const output_file_path = output_file_arg orelse unreachable;

var image = try img.Image.fromFilePath(allocator, input_file_path);
defer image.deinit();

if (image.width != 160 or image.height != 128) {
std.log.err("Image must be 160x128 but it is {}x{}!!!", .{ image.width, image.height });
}

const output_file = try std.fs.cwd().createFile(output_file_path, .{});
defer output_file.close();

const writer = output_file.writer();
try writer.print(
\\const microzig = @import("microzig");
\\const board = microzig.board;
\\const lcd = board.lcd;
\\
\\pub const data = [{}]lcd.Color16 {{
\\
, .{image.height * image.width});
switch (image.pixelFormat()) {
.rgba32 => {
for (image.pixels.rgba32) |pixel| {
const lcd_pixel = img.color.Rgb565.fromU32Rgba(pixel.toU32Rgba());
try writer.print(
\\ .{{ .b = {}, .g = {}, .r = {} }},
\\
, .{
lcd_pixel.b,
lcd_pixel.g,
lcd_pixel.r,
});
}
},
else => {
std.log.err("TODO: {}", .{image.pixelFormat()});
return error.TodoPixelFormat;
},
}

try writer.writeAll(
\\};
\\
);
}
Loading

0 comments on commit 1dfa26c

Please sign in to comment.