Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Build carts for WASM and native targets #31

Merged
merged 3 commits into from
Apr 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading