From 0ffc6cb31d7a9328fae0d819aa5ba1fe96fc35a9 Mon Sep 17 00:00:00 2001 From: Matt Knight Date: Sat, 27 Apr 2024 03:38:26 -0700 Subject: [PATCH] wasm4 -> cart --- build.zig | 230 +++++++++++--------------- samples/feature_test.zig | 52 +++--- samples/zeroman/build/convert_gfx.zig | 2 +- samples/zeroman/main.zig | 12 +- src/cart.zig | 28 ++-- src/{wasm4.zig => cart/api.zig} | 174 ++++++++++--------- 6 files changed, 226 insertions(+), 272 deletions(-) rename src/{wasm4.zig => cart/api.zig} (81%) diff --git a/build.zig b/build.zig index 88598ec..1d3a8f2 100644 --- a/build.zig +++ b/build.zig @@ -10,14 +10,14 @@ 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" }, @@ -25,68 +25,56 @@ pub const sycl_badge_2024 = MicroZig.Target{ 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); - //var dep: std.Build.Dependency = .{ .builder = b }; - //const cart = add_cart(&dep, b, .{ - // .name = "sample", - // .optimize = optimize, - // .root_source_file = .{ .path = "samples/feature_test.zig" }, - //}); - - //const watch_step = b.step("watch", ""); - //watch_step.dependOn(&cart.watch_run_cmd.step); - - //const modified_memory_regions = b.allocator.dupe(MicroZig.MemoryRegion, py_badge.chip.memory_regions) catch @panic("out of memory"); - //for (modified_memory_regions) |*memory_region| { - // if (memory_region.kind != .ram) continue; - // memory_region.offset += 0x19A0; - // memory_region.length -= 0x19A0; - // break; - //} - //var modified_py_badge = py_badge; - //modified_py_badge.chip.memory_regions = modified_memory_regions; - - //const fw = mz.add_firmware(b, .{ - // .name = "pybadge-io", - // .target = modified_py_badge, - // .optimize = optimize, - // .source_file = .{ .path = "src/main.zig" }, - //}); - //fw.artifact.step.dependOn(&fw_options.step); - //fw.modules.app.addImport("options", fw_options.createModule());x - //mz.install_firmware(b, fw, .{}); - //mz.install_firmware(b, fw, .{ .format = .{ .uf2 = .SAMD51 } }); + 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, .{}); @@ -106,7 +94,7 @@ pub fn build(b: *Build) void { }) |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}) }, }); @@ -136,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, }; @@ -156,102 +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 mz = MicroZig.init(d.builder, .{}); - const watch_run_cmd = b.addRunArtifact(watch); - watch_run_cmd.step.dependOn(b.getInstallStep()); - //const watch = d.builder.addExecutable(.{ - // .name = "watch", - // .root_source_file = .{ .path = "src/watch/main.zig" }, - // .target = b.resolveTargetQuery(.{}), - // .optimize = options.optimize, - //}); - //watch.root_module.addImport("ws", d.builder.dependency("ws", .{}).module("websocket")); - //watch.root_module.addImport("mime", d.builder.dependency("mime", .{}).module("mime")); - - //const watch_run_cmd = b.addRunArtifact(watch); - //watch_run_cmd.step.dependOn(b.getInstallStep()); - - //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 cart: *Cart = b.allocator.create(Cart) catch @panic("out of memory"); + 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("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 { @@ -282,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 }; diff --git a/samples/feature_test.zig b/samples/feature_test.zig index 7f0c686..3cf32c7 100644 --- a/samples/feature_test.zig +++ b/samples/feature_test.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const wasm4 = @import("wasm4"); +const cart = @import("cart-api"); export fn start() void {} @@ -9,20 +9,20 @@ var offset: u16 = 0; fn read_stored_number() u64 { var dst: u64 = undefined; - std.debug.assert(wasm4.read_flash(0, std.mem.asBytes(&dst)) == @sizeOf(u64)); + std.debug.assert(cart.read_flash(0, std.mem.asBytes(&dst)) == @sizeOf(u64)); return dst; } fn write_stored_number(number: u64) void { - var page: [wasm4.flash_page_size]u8 = undefined; + var page: [cart.flash_page_size]u8 = undefined; // @as(*u64, @alignCast(@ptrCast(page[0..8]))).* = number; std.mem.bytesAsSlice(u64, &page)[0] = number; - wasm4.write_flash_page(0, page); + cart.write_flash_page(0, page); } export fn update() void { if (offset % (60 * 2) == 0) { - wasm4.tone(440, 20, 10, .{ + cart.tone(440, 20, 10, .{ .channel = .pulse1, .duty_cycle = .@"1/8", .panning = .left, @@ -36,58 +36,58 @@ export fn update() void { fbs.writer().print("{d}\n", .{read_stored_number()}) catch unreachable; - inline for (std.meta.fields(wasm4.Controls)) |control| { + inline for (std.meta.fields(cart.Controls)) |control| { if (comptime !std.mem.eql(u8, control.name, "padding")) { - if (@field(wasm4.controls.*, control.name)) { + if (@field(cart.controls.*, control.name)) { fbs.writer().writeAll(control.name) catch unreachable; fbs.writer().writeAll("\n") catch unreachable; } } } - if (wasm4.controls.up) { + if (cart.controls.up) { green_565 +%= 1; - } else if (wasm4.controls.down) { + } else if (cart.controls.down) { green_565 -%= 1; } - if (wasm4.controls.left) { + if (cart.controls.left) { write_stored_number(read_stored_number() -| 1); - } else if (wasm4.controls.right) { + } else if (cart.controls.right) { write_stored_number(read_stored_number() +| 1); } - wasm4.red_led.* = wasm4.controls.click; + cart.red_led.* = cart.controls.click; - for (0..wasm4.screen_height) |y| { - for (0..wasm4.screen_width) |x| { - wasm4.framebuffer[y * wasm4.screen_width + x] = .{ - .red = @intFromFloat(@as(f32, @floatFromInt(x)) / wasm4.screen_width * 31), + for (0..cart.screen_height) |y| { + for (0..cart.screen_width) |x| { + cart.framebuffer[y * cart.screen_width + x] = .{ + .red = @intFromFloat(@as(f32, @floatFromInt(x)) / cart.screen_width * 31), .green = green_565, - .blue = @intFromFloat(@as(f32, @floatFromInt(y)) / wasm4.screen_height * 31), + .blue = @intFromFloat(@as(f32, @floatFromInt(y)) / cart.screen_height * 31), }; } } - for (wasm4.neopixels, 0..) |*np, i| { + for (cart.neopixels, 0..) |*np, i| { np.* = .{ .red = @intFromFloat(@as(f32, @floatFromInt(i)) / 5 * 255), - .green = @intFromFloat(@as(f32, @floatFromInt(wasm4.light_level.*)) / std.math.maxInt(u12) * 255), + .green = @intFromFloat(@as(f32, @floatFromInt(cart.light_level.*)) / std.math.maxInt(u12) * 255), .blue = @intFromFloat(@as(f32, @floatFromInt(i)) / 5 * 255), }; } // TODO: blit, blitSub - wasm4.line(.{ .red = 0, .green = 63, .blue = 0 }, 50, 50, 70, 70); + cart.line(.{ .red = 0, .green = 63, .blue = 0 }, 50, 50, 70, 70); - wasm4.hline(.{ .red = 31, .green = 0, .blue = 0 }, 30, 30, 20); - wasm4.vline(.{ .red = 31, .green = 0, .blue = 0 }, 30, 30, 20); + cart.hline(.{ .red = 31, .green = 0, .blue = 0 }, 30, 30, 20); + cart.vline(.{ .red = 31, .green = 0, .blue = 0 }, 30, 30, 20); - wasm4.oval(.{ .red = 0, .green = 0, .blue = 31 }, .{ .red = 31, .green = 0, .blue = 31 }, 80, 80, 10, 10); - wasm4.rect(.{ .red = 31, .green = 31, .blue = 31 }, .{ .red = 0, .green = 63, .blue = 31 }, 100, 100, 10, 10); + cart.oval(.{ .red = 0, .green = 0, .blue = 31 }, .{ .red = 31, .green = 0, .blue = 31 }, 80, 80, 10, 10); + cart.rect(.{ .red = 31, .green = 31, .blue = 31 }, .{ .red = 0, .green = 63, .blue = 31 }, 100, 100, 10, 10); - wasm4.text(.{ .red = 0, .green = 0, .blue = 0 }, .{ .red = 31, .green = 63, .blue = 31 }, fbs.getWritten(), 0, 0); + cart.text(.{ .red = 0, .green = 0, .blue = 0 }, .{ .red = 31, .green = 63, .blue = 31 }, fbs.getWritten(), 0, 0); - wasm4.text(.{ .red = 0, .green = 0, .blue = 0 }, .{ .red = 31, .green = 63, .blue = 31 }, "\x80\x81\x82\x83\x84\x85\x86\x87\x88", 0, 120); + cart.text(.{ .red = 0, .green = 0, .blue = 0 }, .{ .red = 31, .green = 63, .blue = 31 }, "\x80\x81\x82\x83\x84\x85\x86\x87\x88", 0, 120); } diff --git a/samples/zeroman/build/convert_gfx.zig b/samples/zeroman/build/convert_gfx.zig index 735c8de..c4042de 100644 --- a/samples/zeroman/build/convert_gfx.zig +++ b/samples/zeroman/build/convert_gfx.zig @@ -32,7 +32,7 @@ pub fn main() !void { const writer = out_file.writer(); try writer.writeAll("const PackedIntSlice = @import(\"std\").packed_int_array.PackedIntSlice;\n"); - try writer.writeAll("const DisplayColor = @import(\"wasm4\").DisplayColor;\n\n"); + try writer.writeAll("const DisplayColor = @import(\"cart-api\").DisplayColor;\n\n"); for (in_files.items) |in_file| { try convert(in_file, writer); diff --git a/samples/zeroman/main.zig b/samples/zeroman/main.zig index eca1ca0..6ca8903 100644 --- a/samples/zeroman/main.zig +++ b/samples/zeroman/main.zig @@ -1,4 +1,4 @@ -const wasm4 = @import("wasm4"); +const cart = @import("cart-api"); const gfx = @import("gfx"); fn blitZero() void { @@ -8,7 +8,7 @@ fn blitZero() void { while (x < 24) : (x += 1) { const index = gfx.zero.indices.get(y * gfx.zero.w + x); if (index == 0) continue; - wasm4.framebuffer[(y + 96) * wasm4.screen_width + x + 80 - 12] = gfx.zero.colors[index]; + cart.framebuffer[(y + 96) * cart.screen_width + x + 80 - 12] = gfx.zero.colors[index]; } } } @@ -20,7 +20,7 @@ fn blitGopher() void { while (x < 24) : (x += 1) { const index = gfx.gopher.indices.get(y * gfx.gopher.w + x); if (index == 0) continue; - wasm4.framebuffer[(y + 104) * wasm4.screen_width + x + 92] = gfx.gopher.colors[index]; + cart.framebuffer[(y + 104) * cart.screen_width + x + 92] = gfx.gopher.colors[index]; } } } @@ -31,7 +31,7 @@ pub fn blitSpriteOpaque(sheet: anytype, dx: u32, dy: u32) void { var x: usize = 0; while (x < sheet.w) : (x += 1) { const index = sheet.indices.get(y * sheet.w + x); - wasm4.framebuffer[(y + dy) * wasm4.screen_width + x + dx] = sheet.colors[index]; + cart.framebuffer[(y + dy) * cart.screen_width + x + dx] = sheet.colors[index]; } } } @@ -43,11 +43,13 @@ pub fn blitSprite(sheet: anytype, dx: u32, dy: u32) void { while (x < sheet.w) : (x += 1) { const index = sheet.indices.get(y * sheet.w + x); if (index == 0) continue; - wasm4.framebuffer[(y + dy) * wasm4.screen_width + x + dx] = sheet.colors[index]; + cart.framebuffer[(y + dy) * cart.screen_width + x + dx] = sheet.colors[index]; } } } +pub export fn start() void {} + pub export fn update() void { blitSpriteOpaque(gfx.needleman, 0, 0); blitSpriteOpaque(gfx.title, 0, 40); diff --git a/src/cart.zig b/src/cart.zig index 080936a..8ad76c6 100644 --- a/src/cart.zig +++ b/src/cart.zig @@ -46,8 +46,8 @@ pub fn init() void { pub fn start() void { call(if (options.have_cart) &libcart.start else &struct { fn start() callconv(.C) void { - const w4 = @import("wasm4.zig"); - w4.trace("start"); + const api = @import("cart/api.zig"); + api.trace("start"); } }.start); } @@ -87,27 +87,27 @@ pub fn tick() void { if (SYSTEM_FLAGS.* & SYSTEM_PRESERVE_FRAMEBUFFER == 0) @memset(FRAMEBUFFER, 0b00_00_00_00); call(if (options.have_cart) &libcart.update else &struct { fn update() callconv(.C) void { - const w4 = @import("wasm4.zig"); + const api = @import("cart/api.zig"); const global = struct { var tick: u8 = 0; var stroke: bool = true; var radius: u32 = 0; var note: usize = 0; }; - w4.PALETTE[0] = 0x000000; - w4.PALETTE[1] = 0xFF0000; - w4.PALETTE[2] = 0xFFFFFF; - w4.DRAW_COLORS.* = if (global.stroke) 0x0032 else 0x0002; - w4.oval( + api.PALETTE[0] = 0x000000; + api.PALETTE[1] = 0xFF0000; + api.PALETTE[2] = 0xFFFFFF; + api.DRAW_COLORS.* = if (global.stroke) 0x0032 else 0x0002; + api.oval( @as(i32, lcd.width / 2) -| @min(global.radius, std.math.maxInt(i32)), @as(i32, lcd.height / 2) -| @min(global.radius, std.math.maxInt(i32)), global.radius * 2, global.radius * 2, ); - w4.DRAW_COLORS.* = 0x0003; + api.DRAW_COLORS.* = 0x0003; for (0..8) |button| { - if (w4.GAMEPAD1.* & @as(u8, 1) << @intCast(button) != 0) { - w4.text( + if (api.GAMEPAD1.* & @as(u8, 1) << @intCast(button) != 0) { + api.text( &.{0x80 + @as(u8, @intCast(button))}, 20 + @as(u8, @intCast(button)) * 16, 60, @@ -125,12 +125,12 @@ pub fn tick() void { } } - w4.tone(([_]u16{ + api.tone(([_]u16{ 880, 831, 784, 740, 698, 659, 622, 587, 554, 523, 494, 466, 440, 415, 392, 370, 349, 330, 311, 294, 277, 262, 247, 233, 220, 207, 196, 185, 175, 165, 156, 147, 139, 131, 123, 117, 110, - })[global.note], 10, 50, w4.TONE_PULSE1); + })[global.note], 10, 50, api.TONE_PULSE1); global.note += 1; if (global.note == 37) global.note = 0; } @@ -545,7 +545,7 @@ const libcart = struct { extern fn __return_thunk__() noreturn; comptime { - if (!options.have_cart) _ = @import("wasm4.zig").__return_thunk__; + if (!options.have_cart) _ = @import("cart/api.zig").__return_thunk__; } }; diff --git a/src/wasm4.zig b/src/cart/api.zig similarity index 81% rename from src/wasm4.zig rename to src/cart/api.zig index 71114b7..fc214d8 100644 --- a/src/wasm4.zig +++ b/src/cart/api.zig @@ -141,30 +141,29 @@ pub inline fn blit_sub(sprite: [*]const u8, x: i32, y: i32, width: u32, height: if (comptime builtin.target.isWasm()) { platform_specific.blit_sub(sprite, x, y, width, height, src_x, src_y, stride, flags); } else { - @compileError("TODO"); - // const rest: extern struct { - // width: u32, - // height: u32, - // src_x: u32, - // src_y: u32, - // stride: u32, - // flags: u32, - // } = .{ - // .width = width, - // .height = height, - // .src_x = src_x, - // .src_y = src_y, - // .stride = stride, - // .flags = flags, - // }; - // asm volatile (" svc #1" - // : - // : [sprite] "{r0}" (sprite), - // [x] "{r1}" (x), - // [y] "{r2}" (y), - // [rest] "{r3}" (&rest), - // : "memory" - // ); + const rest: extern struct { + width: u32, + height: u32, + src_x: u32, + src_y: u32, + stride: u32, + flags: u32, + } = .{ + .width = width, + .height = height, + .src_x = src_x, + .src_y = src_y, + .stride = stride, + .flags = flags, + }; + asm volatile (" svc #1" + : + : [sprite] "{r0}" (sprite), + [x] "{r1}" (x), + [y] "{r2}" (y), + [rest] "{r3}" (&rest), + : "memory" + ); } } @@ -173,15 +172,14 @@ pub inline fn line(color: DisplayColor, x1: i32, y1: i32, x2: i32, y2: i32) void if (comptime builtin.target.isWasm()) { platform_specific.line(color, x1, y1, x2, y2); } else { - @compileError("TODO"); - // asm volatile (" svc #2" - // : - // : [x1] "{r0}" (x1), - // [y1] "{r1}" (y1), - // [x2] "{r2}" (x2), - // [y2] "{r3}" (y2), - // : "memory" - // ); + asm volatile (" svc #2" + : + : [x1] "{r0}" (x1), + [y1] "{r1}" (y1), + [x2] "{r2}" (x2), + [y2] "{r3}" (y2), + : "memory" + ); } } @@ -190,15 +188,14 @@ pub inline fn oval(stroke_color: ?DisplayColor, fill_color: ?DisplayColor, x: i3 if (comptime builtin.target.isWasm()) { platform_specific.oval(OptionalDisplayColor.from(stroke_color), OptionalDisplayColor.from(fill_color), x, y, width, height); } else { - @compileError("TODO"); - // asm volatile (" svc #3" - // : - // : [x] "{r0}" (x), - // [y] "{r1}" (y), - // [width] "{r2}" (width), - // [height] "{r3}" (height), - // : "memory" - // ); + asm volatile (" svc #3" + : + : [x] "{r0}" (x), + [y] "{r1}" (y), + [width] "{r2}" (width), + [height] "{r3}" (height), + : "memory" + ); } } @@ -207,15 +204,14 @@ pub inline fn rect(stroke_color: ?DisplayColor, fill_color: ?DisplayColor, x: i3 if (comptime builtin.target.isWasm()) { platform_specific.rect(OptionalDisplayColor.from(stroke_color), OptionalDisplayColor.from(fill_color), x, y, width, height); } else { - @compileError("TODO"); - // asm volatile (" svc #4" - // : - // : [x] "{r0}" (x), - // [y] "{r1}" (y), - // [width] "{r2}" (width), - // [height] "{r3}" (height), - // : "memory" - // ); + asm volatile (" svc #4" + : + : [x] "{r0}" (x), + [y] "{r1}" (y), + [width] "{r2}" (width), + [height] "{r3}" (height), + : "memory" + ); } } @@ -224,15 +220,14 @@ pub inline fn text(text_color: DisplayColor, background_color: ?DisplayColor, st if (comptime builtin.target.isWasm()) { platform_specific.text(text_color, OptionalDisplayColor.from(background_color), str.ptr, str.len, x, y); } else { - @compileError("TODO"); - // asm volatile (" svc #5" - // : - // : [str_ptr] "{r0}" (str.ptr), - // [str_len] "{r1}" (str.len), - // [x] "{r2}" (x), - // [y] "{r3}" (y), - // : "memory" - // ); + asm volatile (" svc #5" + : + : [str_ptr] "{r0}" (str.ptr), + [str_len] "{r1}" (str.len), + [x] "{r2}" (x), + [y] "{r3}" (y), + : "memory" + ); } } @@ -241,14 +236,13 @@ pub inline fn hline(color: DisplayColor, x: i32, y: i32, len: u32) void { if (comptime builtin.target.isWasm()) { platform_specific.hline(color, x, y, len); } else { - @compileError("TODO"); - // asm volatile (" svc #7" - // : - // : [x] "{r0}" (x), - // [y] "{r1}" (y), - // [len] "{r2}" (len), - // : "memory" - // ); + asm volatile (" svc #7" + : + : [x] "{r0}" (x), + [y] "{r1}" (y), + [len] "{r2}" (len), + : "memory" + ); } } @@ -257,14 +251,13 @@ pub inline fn vline(color: DisplayColor, x: i32, y: i32, len: u32) void { if (comptime builtin.target.isWasm()) { platform_specific.vline(color, x, y, len); } else { - @compileError("TODO"); - // asm volatile (" svc #6" - // : - // : [x] "{r0}" (x), - // [y] "{r1}" (y), - // [len] "{r2}" (len), - // : "memory" - // ); + asm volatile (" svc #6" + : + : [x] "{r0}" (x), + [y] "{r1}" (y), + [len] "{r2}" (len), + : "memory" + ); } } @@ -306,14 +299,13 @@ pub inline fn tone(frequency: u32, duration: u32, volume: u32, flags: ToneFlags) if (comptime builtin.target.isWasm()) { platform_specific.tone(frequency, duration, volume, flags); } else { - @compileError("TODO"); - // asm volatile (" svc #8" - // : - // : [frequency] "{r0}" (frequency), - // [duration] "{r1}" (duration), - // [volume] "{r2}" (volume), - // [flags] "{r3}" (flags), - // ); + asm volatile (" svc #8" + : + : [frequency] "{r0}" (frequency), + [duration] "{r1}" (duration), + [volume] "{r2}" (volume), + [flags] "{r3}" (flags), + ); } } @@ -331,7 +323,7 @@ pub inline fn read_flash(offset: u32, dst: []u8) u32 { if (comptime builtin.target.isWasm()) { return platform_specific.read_flash(offset, dst.ptr, dst.len); } else { - @compileError("TODO"); + @panic("TODO"); } } @@ -339,12 +331,12 @@ pub inline fn write_flash_page(page: u16, src: [flash_page_size]u8) void { if (comptime builtin.target.isWasm()) { return platform_specific.write_flash_page(page, &src); } else { - @compileError("TODO"); - // return asm volatile (" svc #10" - // : [result] "={r0}" (-> u32), - // : [src] "{r0}" (src), - // [size] "{r1}" (size), - // ); + // TODO: return? + _ = asm volatile (" svc #10" + : [result] "={r0}" (-> u32), + : [src] "{r0}" (src), + [size] "{r1}" (flash_page_size), + ); } }