diff --git a/board-support/raspberrypi-rp2040/build.zig b/board-support/raspberrypi-rp2040/build.zig index 3e0d534..1baf71e 100644 --- a/board-support/raspberrypi-rp2040/build.zig +++ b/board-support/raspberrypi-rp2040/build.zig @@ -137,15 +137,15 @@ const chip = .{ }; /// Returns a configuration function that will add the provided `BootROM` to the firmware. -pub fn rp2040_configure(comptime bootrom: BootROM) *const fn (host_build: *std.Build, *microzig.Firmware) void { +pub fn rp2040_configure(comptime bootrom: BootROM) *const fn (env: *microzig.BuildEnvironment, *microzig.Firmware) void { const T = struct { - fn configure(host_build: *std.Build, fw: *microzig.Firmware) void { - const bootrom_file = getBootrom(host_build, bootrom); + fn configure(env: *microzig.BuildEnvironment, fw: *microzig.Firmware) void { + const bootrom_file = getBootrom(env, bootrom); // HACK: Inject the file as a dependency to MicroZig.board fw.modules.board.?.dependencies.put( "bootloader", - host_build.createModule(.{ + env.host_build.createModule(.{ .source_file = bootrom_file.bin, }), ) catch @panic("oom"); @@ -161,7 +161,7 @@ pub const Stage2Bootloader = struct { elf: ?std.Build.LazyPath, }; -pub fn getBootrom(b: *std.Build, rom: BootROM) Stage2Bootloader { +pub fn getBootrom(env: *microzig.BuildEnvironment, rom: BootROM) Stage2Bootloader { const rom_exe = switch (rom) { .artifact => |artifact| artifact, .blob => |blob| return Stage2Bootloader{ @@ -170,13 +170,13 @@ pub fn getBootrom(b: *std.Build, rom: BootROM) Stage2Bootloader { }, else => blk: { - var target = @as(microzig.CpuModel, chip.cpu).getDescriptor().target; + var target = env.getCpuDescriptor(chip.cpu).target; target.abi = .eabi; - const rom_path = b.pathFromRoot(b.fmt("{s}/src/bootroms/{s}.S", .{ build_root, @tagName(rom) })); + const rom_path = env.host_build.pathFromRoot(env.host_build.fmt("{s}/src/bootroms/{s}.S", .{ build_root, @tagName(rom) })); - const rom_exe = b.addExecutable(.{ - .name = b.fmt("stage2-{s}", .{@tagName(rom)}), + const rom_exe = env.host_build.addExecutable(.{ + .name = env.host_build.fmt("stage2-{s}", .{@tagName(rom)}), .optimize = .ReleaseSmall, .target = target, .root_source_file = null, @@ -191,8 +191,8 @@ pub fn getBootrom(b: *std.Build, rom: BootROM) Stage2Bootloader { }, }; - const rom_objcopy = b.addObjCopy(rom_exe.getEmittedBin(), .{ - .basename = b.fmt("{s}.bin", .{@tagName(rom)}), + const rom_objcopy = env.host_build.addObjCopy(rom_exe.getEmittedBin(), .{ + .basename = env.host_build.fmt("{s}.bin", .{@tagName(rom)}), .format = .bin, }); diff --git a/build/build.zig b/build/build.zig index 67c16e2..8150551 100644 --- a/build/build.zig +++ b/build/build.zig @@ -5,10 +5,64 @@ const std = @import("std"); const uf2 = @import("uf2"); +/// This build script validates usage patterns we expect from MicroZig +pub fn build(b: *std.Build) !void { + const uf2_dep = b.dependency("uf2", .{}); + + const build_test = b.addTest(.{ + .root_source_file = .{ .path = "build.zig" }, + }); + + build_test.addAnonymousModule("uf2", .{ + .source_file = .{ .cwd_relative = uf2_dep.builder.pathFromRoot("build.zig") }, + }); + + const install_docs = b.addInstallDirectory(.{ + .source_dir = build_test.getEmittedDocs(), + .install_dir = .prefix, + .install_subdir = "docs", + }); + + b.getInstallStep().dependOn(&install_docs.step); +} + //////////////////////////////////////// // MicroZig Gen 3 Interface // //////////////////////////////////////// +const zig_deps = struct { + // Keep in sync with the logic from Build.zig:dependency: + + const build_runner = @import("root"); + const deps = build_runner.dependencies; + + const names = blk: { + var list: []const []const u8 = &.{}; + for (@typeInfo(deps.imports).Struct.decls) |decl| { + list = list ++ [_][]const u8{decl.name}; + } + break :blk list; + }; + + const modules = blk: { + var list: []const type = &.{}; + for (@typeInfo(deps.imports).Struct.decls) |decl| { + list = list ++ [_]type{@field(deps.imports, decl.name)}; + } + break :blk list; + }; + + fn get(comptime name: []const u8) ?type { + for (names, modules) |item, mod| { + if (std.mem.eql(u8, item, name)) + return mod; + } + return null; + } +}; + +pub const CpuArray = std.enums.EnumArray(CpuType, Cpu); + pub const BoardSupportPackageDefinition = struct { pub const TargetDefinition = struct { id: []const u8, // full "uri" @@ -109,21 +163,14 @@ const ImportedBSP = struct { }; fn get_declared_bsps() []const ImportedBSP { - - // Keep in sync with the logic from Build.zig:dependency - const build_runner = @import("root"); - const deps = build_runner.dependencies; - var bsps: []const ImportedBSP = &.{}; - inline for (@typeInfo(deps.imports).Struct.decls) |decl| { - if (comptime std.mem.indexOfScalar(u8, decl.name, '.') == null) { - const maybe_bsp = @field(deps.imports, decl.name); - + inline for (zig_deps.names, zig_deps.modules) |name, maybe_bsp| { + if (comptime std.mem.indexOfScalar(u8, name, '.') == null) { if (@hasDecl(maybe_bsp, "microzig_board_support")) { const bsp = @field(maybe_bsp, "microzig_board_support"); if (@TypeOf(bsp) == BoardSupportPackageDefinition) { bsps = bsps ++ [_]ImportedBSP{.{ - .import_name = decl.name, + .import_name = name, .bsp = bsp, }}; } @@ -139,24 +186,72 @@ pub const EnvironmentInfo = struct { /// package name of the core package (optional) core: []const u8 = "microzig-core", + + board_support_packages: BspSource = .from_dependencies, + + pub const BspSource = union(enum) { + from_dependencies, + explicit: []const []const u8, + }; }; +/// Creates a new MicroZig build environment that can be used to create new firmware. pub fn createBuildEnvironment(b: *std.Build, comptime info: EnvironmentInfo) *BuildEnvironment { const available_bsps = comptime get_declared_bsps(); + const requested_bsps = switch (info.board_support_packages) { + .from_dependencies => available_bsps, + .explicit => |list| comptime blk: { + var used = std.StaticBitSet(list.len).initEmpty(); + + var requested_bsps: []const ImportedBSP = &.{}; + for (list, 0..) |name, index| { + for (available_bsps) |bsp| { + if (std.mem.eql(u8, bsp.name, name)) { + requested_bsps = requested_bsps ++ [_]ImportedBSP{bsp}; + } else { + used.set(index); + } + } + } + + if (used.count > 0) { + var msg: []const u8 = "Not all requested board support packages were declared in build.zig.zon. The following packages are missing:"; + var iter = used.iterator(); + while (iter.next()) |index| { + msg = msg ++ std.fmt.comptimePrint("\n* {s}", .{ + list[index].name, + }); + } + @compileError(msg); + } + + break :blk requested_bsps; + }, + }; + + const core_module = zig_deps.get(info.core) orelse @compileError("A module named " ++ info.core ++ " is not declared in build.zig.zon!"); + const build_module = zig_deps.get(info.self) orelse @compileError("A module named " ++ info.self ++ " is not declared in build.zig.zon!"); + if (build_module != @This()) { + @compileError("The module " ++ info.self ++ " is not the same of which this function is called. Please pass the exact same module name to this function as you pass to import!"); + } + const be = b.allocator.create(BuildEnvironment) catch @panic("out of memory"); be.* = BuildEnvironment{ .host_build = b, .self = undefined, .microzig_core = undefined, - .board_support_packages = b.allocator.alloc(BoardSupportPackage, available_bsps.len) catch @panic("out of memory"), + .board_support_packages = b.allocator.alloc(BoardSupportPackage, requested_bsps.len) catch @panic("out of memory"), .targets = .{}, + .self_pkg_name = comptime info.self, + .core_pkg_name = comptime info.core, + .cpus = &core_module.cpus, }; be.self = b.dependency(info.self, .{}); be.microzig_core = b.dependency(info.core, .{}); - inline for (be.board_support_packages, available_bsps) |*bsp, def| { + inline for (be.board_support_packages, requested_bsps) |*bsp, def| { bsp.* = BoardSupportPackage{ .name = def.import_name, .dep = b.dependency(def.import_name, .{}), @@ -184,14 +279,28 @@ pub const BuildEnvironment = struct { microzig_core: *std.Build.Dependency, + self_pkg_name: []const u8, + core_pkg_name: []const u8, + board_support_packages: []BoardSupportPackage, targets: std.StringArrayHashMapUnmanaged(Target), + cpus: *const CpuArray, + + /// Searches for a target called `name` and returns a pointer to the MicroZig Target if it exists. pub fn findTarget(env: *const BuildEnvironment, name: []const u8) ?*const Target { return env.targets.getPtr(name); } + /// Returns the instance to the CPU descriptor for the given CPU model. + pub fn getCpuDescriptor(env: *BuildEnvironment, model: CpuModel) *const Cpu { + return if (model == .custom) + model.custom + else + env.cpus.getPtrConst(model); + } + /// Declares a new MicroZig firmware file. pub fn addFirmware( /// The MicroZig instance that should be used to create the firmware. @@ -204,7 +313,7 @@ pub const BuildEnvironment = struct { const micro_build = env.self.builder; const chip = &options.target.chip; - const cpu = chip.cpu.getDescriptor(); + const cpu = env.getCpuDescriptor(chip.cpu); const maybe_hal = options.hal orelse options.target.hal; const maybe_board = options.board orelse options.target.board; @@ -259,7 +368,7 @@ pub const BuildEnvironment = struct { .optimize = options.optimize, .target = cpu.target, .linkage = .static, - .root_source_file = .{ .cwd_relative = env.self.builder.pathFromRoot("src/start.zig") }, + .root_source_file = .{ .cwd_relative = env.microzig_core.builder.pathFromRoot("src/start.zig") }, }), .target = options.target, .output_files = Firmware.OutputFileMap.init(host_build.allocator), @@ -268,7 +377,7 @@ pub const BuildEnvironment = struct { .modules = .{ .microzig = micro_build.createModule(.{ - .source_file = .{ .cwd_relative = micro_build.pathFromRoot("src/microzig.zig") }, + .source_file = .{ .cwd_relative = env.microzig_core.builder.pathFromRoot("src/microzig.zig") }, .dependencies = &.{ .{ .name = "config", @@ -331,7 +440,7 @@ pub const BuildEnvironment = struct { }, }); - const umm = env.dependency("umm-zig", .{}).module("umm"); + const umm = env.microzig_core.builder.dependency("umm-zig", .{}).module("umm"); fw.modules.microzig.dependencies.put("umm", umm) catch @panic("out of memory"); fw.artifact.addModule("app", fw.modules.app); @@ -344,7 +453,7 @@ pub const BuildEnvironment = struct { switch (linker_script) { .generated => { fw.artifact.setLinkerScript( - generateLinkerScript(host_build, chip.*) catch @panic("out of memory"), + env.generateLinkerScript(chip.*) catch @panic("out of memory"), ); }, @@ -354,7 +463,7 @@ pub const BuildEnvironment = struct { } if (options.target.configure) |configure| { - configure(host_build, fw); + configure(fw.env, fw); } return fw; @@ -404,98 +513,145 @@ pub const BuildEnvironment = struct { fn dependency(env: *BuildEnvironment, name: []const u8, args: anytype) *std.Build.Dependency { return env.self.builder.dependency(name, args); } -}; -//////////////////////////////////////// -// MicroZig Gen 2 Interface // -//////////////////////////////////////// + fn generateLinkerScript(env: *BuildEnvironment, chip: Chip) !std.Build.LazyPath { + const cpu = env.getCpuDescriptor(chip.cpu); + + var contents = std.ArrayList(u8).init(env.host_build.allocator); + const writer = contents.writer(); + try writer.print( + \\/* + \\ * This file was auto-generated by microzig + \\ * + \\ * Target CPU: {[cpu]s} + \\ * Target Chip: {[chip]s} + \\ */ + \\ + // This is not the "true" entry point, but there's no such thing on embedded platforms + // anyways. This is the logical entrypoint that should be invoked when + // stack, .data and .bss are set up and the CPU is ready to be used. + \\ENTRY(microzig_main); + \\ + \\ + , .{ + .cpu = cpu.name, + .chip = chip.name, + }); -fn root() []const u8 { - return comptime (std.fs.path.dirname(@src().file) orelse "."); -} -const build_root = root(); + try writer.writeAll("MEMORY\n{\n"); + { + var counters = [4]usize{ 0, 0, 0, 0 }; + for (chip.memory_regions) |region| { + // flash (rx!w) : ORIGIN = 0x00000000, LENGTH = 512k -const MicroZig = @This(); + switch (region.kind) { + .flash => { + try writer.print(" flash{d} (rx!w)", .{counters[0]}); + counters[0] += 1; + }, -b: *std.Build, -self: *std.Build.Dependency, + .ram => { + try writer.print(" ram{d} (rw!x)", .{counters[1]}); + counters[1] += 1; + }, -/// Creates a new instance of the MicroZig build support. -/// -/// This is necessary as we need to keep track of some internal state to prevent -/// duplicated work per firmware built. -pub fn init(b: *std.Build, dependency_name: []const u8) *MicroZig { - const mz = b.allocator.create(MicroZig) catch @panic("out of memory"); - mz.* = MicroZig{ - .b = b, - .self = b.dependency(dependency_name, .{}), - }; - return mz; -} + .io => { + try writer.print(" io{d} (rw!x)", .{counters[2]}); + counters[2] += 1; + }, -/// This build script validates usage patterns we expect from MicroZig -pub fn build(b: *std.Build) !void { - const uf2_dep = b.dependency("uf2", .{}); + .reserved => { + try writer.print(" reserved{d} (rw!x)", .{counters[3]}); + counters[3] += 1; + }, - const build_test = b.addTest(.{ - .root_source_file = .{ .path = "build.zig" }, - }); + .private => |custom| { + try writer.print(" {s} (", .{custom.name}); + if (custom.readable) try writer.writeAll("r"); + if (custom.writeable) try writer.writeAll("w"); + if (custom.executable) try writer.writeAll("x"); + + if (!custom.readable or !custom.writeable or !custom.executable) { + try writer.writeAll("!"); + if (!custom.readable) try writer.writeAll("r"); + if (!custom.writeable) try writer.writeAll("w"); + if (!custom.executable) try writer.writeAll("x"); + } + try writer.writeAll(")"); + }, + } + try writer.print(" : ORIGIN = 0x{X:0>8}, LENGTH = 0x{X:0>8}\n", .{ region.offset, region.length }); + } + } - build_test.addAnonymousModule("uf2", .{ - .source_file = .{ .cwd_relative = uf2_dep.builder.pathFromRoot("build.zig") }, - }); + try writer.writeAll("}\n\nSECTIONS\n{\n"); + { + try writer.writeAll( + \\ .text : + \\ { + \\ KEEP(*(microzig_flash_start)) + \\ *(.text*) + \\ } > flash0 + \\ + \\ + ); + + switch (cpu.target.getCpuArch()) { + .arm, .thumb => try writer.writeAll( + \\ .ARM.exidx : { + \\ *(.ARM.exidx* .gnu.linkonce.armexidx.*) + \\ } >flash0 + \\ + \\ + ), + else => {}, + } - const install_docs = b.addInstallDirectory(.{ - .source_dir = build_test.getEmittedDocs(), - .install_dir = .prefix, - .install_subdir = "docs", - }); + try writer.writeAll( + \\ .data : + \\ { + \\ microzig_data_start = .; + \\ *(.rodata*) + \\ *(.data*) + \\ microzig_data_end = .; + \\ } > ram0 AT> flash0 + \\ + \\ .bss (NOLOAD) : + \\ { + \\ microzig_bss_start = .; + \\ *(.bss*) + \\ microzig_bss_end = .; + \\ } > ram0 + \\ + \\ microzig_data_load_start = LOADADDR(.data); + \\ + ); + } + try writer.writeAll("}\n"); - b.getInstallStep().dependOn(&install_docs.step); + // TODO: Assert that the flash can actually hold all data! + // try writer.writeAll( + // \\ + // \\ ASSERT( (SIZEOF(.text) + SIZEOF(.data) > LENGTH(flash0)), "Error: .text + .data is too large for flash!" ); + // \\ + // ); + + const write = env.host_build.addWriteFiles(); + + return write.add("linker.ld", contents.items); + } +}; - // const backings = @import("test/backings.zig"); - // const optimize = b.standardOptimizeOption(.{}); - - // const minimal = addEmbeddedExecutable(b, .{ - // .name = "minimal", - // .source_file = .{ - // .path = comptime root_dir() ++ "/test/programs/minimal.zig", - // }, - // .backing = backings.minimal, - // .optimize = optimize, - // }); - - // const has_hal = addEmbeddedExecutable(b, .{ - // .name = "has_hal", - // .source_file = .{ - // .path = comptime root_dir() ++ "/test/programs/has_hal.zig", - // }, - // .backing = backings.has_hal, - // .optimize = optimize, - // }); - - // const has_board = addEmbeddedExecutable(b, .{ - // .name = "has_board", - // .source_file = .{ - // .path = comptime root_dir() ++ "/test/programs/has_board.zig", - // }, - // .backing = backings.has_board, - // .optimize = optimize, - // }); - - // const core_tests = b.addTest(.{ - // .root_source_file = .{ - // .path = comptime root_dir() ++ "/src/core.zig", - // }, - // .optimize = optimize, - // }); - - // const test_step = b.step("test", "build test programs"); - // test_step.dependOn(&minimal.inner.step); - // test_step.dependOn(&has_hal.inner.step); - // test_step.dependOn(&has_board.inner.step); - // test_step.dependOn(&b.addRunArtifact(core_tests).step); +//////////////////////////////////////// +// MicroZig Gen 2 Interface // +//////////////////////////////////////// + +fn root() []const u8 { + return comptime (std.fs.path.dirname(@src().file) orelse "."); } +const build_root = root(); + +const MicroZig = @This(); /// The resulting binary format for the firmware file. /// A lot of embedded systems don't use plain ELF files, thus we provide means @@ -602,17 +758,12 @@ pub const CpuModel = union(enum) { cortex_m3, cortex_m4, riscv32_imac, - custom: *const Cpu, - - pub fn getDescriptor(model: CpuModel) *const Cpu { - return switch (@as(std.meta.Tag(CpuModel), model)) { - inline else => |tag| &@field(cpus, @tagName(tag)), - .custom => model.custom, - }; - } }; +/// Tag of CpuModel +pub const CpuType = std.meta.Tag(CpuModel); + /// A cpu descriptor. pub const Cpu = struct { /// Display name of the CPU. @@ -761,7 +912,7 @@ pub const Target = struct { /// (optional) Further configures the created firmware depending on the chip and/or board settings. /// This can be used to set/change additional properties on the created `*Firmware` object. - configure: ?*const fn (host_build: *std.Build, *Firmware) void = null, + configure: ?*const fn (env: *BuildEnvironment, *Firmware) void = null, /// (optional) Post processing step that will patch up and modify the elf file if necessary. binary_post_process: ?*const fn (host_build: *std.Build, std.Build.LazyPath) std.Build.LazyPath = null, @@ -965,202 +1116,7 @@ pub const Firmware = struct { } }; -pub const cpus = struct { - pub const avr5 = Cpu{ - .name = "AVR5", - .source_file = .{ .path = build_root ++ "/src/cpus/avr5.zig" }, - .target = std.zig.CrossTarget{ - .cpu_arch = .avr, - .cpu_model = .{ .explicit = &std.Target.avr.cpu.avr5 }, - .os_tag = .freestanding, - .abi = .eabi, - }, - }; - - pub const cortex_m0 = Cpu{ - .name = "ARM Cortex-M0", - .source_file = .{ .path = build_root ++ "/src/cpus/cortex-m.zig" }, - .target = std.zig.CrossTarget{ - .cpu_arch = .thumb, - .cpu_model = .{ .explicit = &std.Target.arm.cpu.cortex_m0 }, - .os_tag = .freestanding, - .abi = .eabi, - }, - }; - - pub const cortex_m0plus = Cpu{ - .name = "ARM Cortex-M0+", - .source_file = .{ .path = build_root ++ "/src/cpus/cortex-m.zig" }, - .target = std.zig.CrossTarget{ - .cpu_arch = .thumb, - .cpu_model = .{ .explicit = &std.Target.arm.cpu.cortex_m0plus }, - .os_tag = .freestanding, - .abi = .eabi, - }, - }; - - pub const cortex_m3 = Cpu{ - .name = "ARM Cortex-M3", - .source_file = .{ .path = build_root ++ "/src/cpus/cortex-m.zig" }, - .target = std.zig.CrossTarget{ - .cpu_arch = .thumb, - .cpu_model = .{ .explicit = &std.Target.arm.cpu.cortex_m3 }, - .os_tag = .freestanding, - .abi = .eabi, - }, - }; - - pub const cortex_m4 = Cpu{ - .name = "ARM Cortex-M4", - .source_file = .{ .path = build_root ++ "/src/cpus/cortex-m.zig" }, - .target = std.zig.CrossTarget{ - .cpu_arch = .thumb, - .cpu_model = .{ .explicit = &std.Target.arm.cpu.cortex_m4 }, - .os_tag = .freestanding, - .abi = .eabi, - }, - }; - - pub const riscv32_imac = Cpu{ - .name = "RISC-V 32-bit", - .source_file = .{ .path = build_root ++ "/src/cpus/riscv32.zig" }, - .target = std.zig.CrossTarget{ - .cpu_arch = .riscv32, - .cpu_model = .{ .explicit = &std.Target.riscv.cpu.sifive_e21 }, - .os_tag = .freestanding, - .abi = .none, - }, - }; -}; - fn buildConfigError(b: *std.Build, comptime fmt: []const u8, args: anytype) noreturn { const msg = b.fmt(fmt, args); @panic(msg); } - -fn generateLinkerScript(b: *std.Build, chip: Chip) !std.Build.LazyPath { - const cpu = chip.cpu.getDescriptor(); - - var contents = std.ArrayList(u8).init(b.allocator); - const writer = contents.writer(); - try writer.print( - \\/* - \\ * This file was auto-generated by microzig - \\ * - \\ * Target CPU: {[cpu]s} - \\ * Target Chip: {[chip]s} - \\ */ - \\ - // This is not the "true" entry point, but there's no such thing on embedded platforms - // anyways. This is the logical entrypoint that should be invoked when - // stack, .data and .bss are set up and the CPU is ready to be used. - \\ENTRY(microzig_main); - \\ - \\ - , .{ - .cpu = cpu.name, - .chip = chip.name, - }); - - try writer.writeAll("MEMORY\n{\n"); - { - var counters = [4]usize{ 0, 0, 0, 0 }; - for (chip.memory_regions) |region| { - // flash (rx!w) : ORIGIN = 0x00000000, LENGTH = 512k - - switch (region.kind) { - .flash => { - try writer.print(" flash{d} (rx!w)", .{counters[0]}); - counters[0] += 1; - }, - - .ram => { - try writer.print(" ram{d} (rw!x)", .{counters[1]}); - counters[1] += 1; - }, - - .io => { - try writer.print(" io{d} (rw!x)", .{counters[2]}); - counters[2] += 1; - }, - - .reserved => { - try writer.print(" reserved{d} (rw!x)", .{counters[3]}); - counters[3] += 1; - }, - - .private => |custom| { - try writer.print(" {s} (", .{custom.name}); - if (custom.readable) try writer.writeAll("r"); - if (custom.writeable) try writer.writeAll("w"); - if (custom.executable) try writer.writeAll("x"); - - if (!custom.readable or !custom.writeable or !custom.executable) { - try writer.writeAll("!"); - if (!custom.readable) try writer.writeAll("r"); - if (!custom.writeable) try writer.writeAll("w"); - if (!custom.executable) try writer.writeAll("x"); - } - try writer.writeAll(")"); - }, - } - try writer.print(" : ORIGIN = 0x{X:0>8}, LENGTH = 0x{X:0>8}\n", .{ region.offset, region.length }); - } - } - - try writer.writeAll("}\n\nSECTIONS\n{\n"); - { - try writer.writeAll( - \\ .text : - \\ { - \\ KEEP(*(microzig_flash_start)) - \\ *(.text*) - \\ } > flash0 - \\ - \\ - ); - - switch (cpu.target.getCpuArch()) { - .arm, .thumb => try writer.writeAll( - \\ .ARM.exidx : { - \\ *(.ARM.exidx* .gnu.linkonce.armexidx.*) - \\ } >flash0 - \\ - \\ - ), - else => {}, - } - - try writer.writeAll( - \\ .data : - \\ { - \\ microzig_data_start = .; - \\ *(.rodata*) - \\ *(.data*) - \\ microzig_data_end = .; - \\ } > ram0 AT> flash0 - \\ - \\ .bss (NOLOAD) : - \\ { - \\ microzig_bss_start = .; - \\ *(.bss*) - \\ microzig_bss_end = .; - \\ } > ram0 - \\ - \\ microzig_data_load_start = LOADADDR(.data); - \\ - ); - } - try writer.writeAll("}\n"); - - // TODO: Assert that the flash can actually hold all data! - // try writer.writeAll( - // \\ - // \\ ASSERT( (SIZEOF(.text) + SIZEOF(.data) > LENGTH(flash0)), "Error: .text + .data is too large for flash!" ); - // \\ - // ); - - const write = b.addWriteFiles(); - - return write.add("linker.ld", contents.items); -} diff --git a/core/build.zig b/core/build.zig index 0337090..2d6008f 100644 --- a/core/build.zig +++ b/core/build.zig @@ -13,70 +13,10 @@ const build_root = root(); /// This build script validates usage patterns we expect from MicroZig pub fn build(b: *std.Build) !void { _ = b; - // const uf2_dep = b.dependency("uf2", .{}); - - // const build_test = b.addTest(.{ - // .root_source_file = .{ .path = "build.zig" }, - // }); - - // build_test.addAnonymousModule("uf2", .{ - // .source_file = .{ .cwd_relative = uf2_dep.builder.pathFromRoot("build.zig") }, - // }); - - // const install_docs = b.addInstallDirectory(.{ - // .source_dir = build_test.getEmittedDocs(), - // .install_dir = .prefix, - // .install_subdir = "docs", - // }); - - // b.getInstallStep().dependOn(&install_docs.step); - - // const backings = @import("test/backings.zig"); - // const optimize = b.standardOptimizeOption(.{}); - - // const minimal = addEmbeddedExecutable(b, .{ - // .name = "minimal", - // .source_file = .{ - // .path = comptime root_dir() ++ "/test/programs/minimal.zig", - // }, - // .backing = backings.minimal, - // .optimize = optimize, - // }); - - // const has_hal = addEmbeddedExecutable(b, .{ - // .name = "has_hal", - // .source_file = .{ - // .path = comptime root_dir() ++ "/test/programs/has_hal.zig", - // }, - // .backing = backings.has_hal, - // .optimize = optimize, - // }); - - // const has_board = addEmbeddedExecutable(b, .{ - // .name = "has_board", - // .source_file = .{ - // .path = comptime root_dir() ++ "/test/programs/has_board.zig", - // }, - // .backing = backings.has_board, - // .optimize = optimize, - // }); - - // const core_tests = b.addTest(.{ - // .root_source_file = .{ - // .path = comptime root_dir() ++ "/src/core.zig", - // }, - // .optimize = optimize, - // }); - - // const test_step = b.step("test", "build test programs"); - // test_step.dependOn(&minimal.inner.step); - // test_step.dependOn(&has_hal.inner.step); - // test_step.dependOn(&has_board.inner.step); - // test_step.dependOn(&b.addRunArtifact(core_tests).step); } -pub const cpus = struct { - pub const avr5 = microbuild.Cpu{ +pub const cpus = microbuild.CpuArray.init(.{ + .avr5 = microbuild.Cpu{ .name = "AVR5", .source_file = .{ .path = build_root ++ "/src/cpus/avr5.zig" }, .target = std.zig.CrossTarget{ @@ -85,9 +25,9 @@ pub const cpus = struct { .os_tag = .freestanding, .abi = .eabi, }, - }; + }, - pub const cortex_m0 = microbuild.Cpu{ + .cortex_m0 = microbuild.Cpu{ .name = "ARM Cortex-M0", .source_file = .{ .path = build_root ++ "/src/cpus/cortex-m.zig" }, .target = std.zig.CrossTarget{ @@ -96,9 +36,9 @@ pub const cpus = struct { .os_tag = .freestanding, .abi = .eabi, }, - }; + }, - pub const cortex_m0plus = microbuild.Cpu{ + .cortex_m0plus = microbuild.Cpu{ .name = "ARM Cortex-M0+", .source_file = .{ .path = build_root ++ "/src/cpus/cortex-m.zig" }, .target = std.zig.CrossTarget{ @@ -107,9 +47,9 @@ pub const cpus = struct { .os_tag = .freestanding, .abi = .eabi, }, - }; + }, - pub const cortex_m3 = microbuild.Cpu{ + .cortex_m3 = microbuild.Cpu{ .name = "ARM Cortex-M3", .source_file = .{ .path = build_root ++ "/src/cpus/cortex-m.zig" }, .target = std.zig.CrossTarget{ @@ -118,9 +58,9 @@ pub const cpus = struct { .os_tag = .freestanding, .abi = .eabi, }, - }; + }, - pub const cortex_m4 = microbuild.Cpu{ + .cortex_m4 = microbuild.Cpu{ .name = "ARM Cortex-M4", .source_file = .{ .path = build_root ++ "/src/cpus/cortex-m.zig" }, .target = std.zig.CrossTarget{ @@ -129,9 +69,9 @@ pub const cpus = struct { .os_tag = .freestanding, .abi = .eabi, }, - }; + }, - pub const riscv32_imac = microbuild.Cpu{ + .riscv32_imac = microbuild.Cpu{ .name = "RISC-V 32-bit", .source_file = .{ .path = build_root ++ "/src/cpus/riscv32.zig" }, .target = std.zig.CrossTarget{ @@ -140,5 +80,7 @@ pub const cpus = struct { .os_tag = .freestanding, .abi = .none, }, - }; -}; + }, + + .custom = undefined, +}); diff --git a/examples/next-gen/build.zig.zon b/examples/next-gen/build.zig.zon index 9053967..ce5dbe8 100644 --- a/examples/next-gen/build.zig.zon +++ b/examples/next-gen/build.zig.zon @@ -4,19 +4,19 @@ .dependencies = .{ .microzig = .{ .url = "https://public.devspace.random-projects.net/microzig-build.tar.gz", - .hash = "1220c87cc608598bdb4ae5ed6436c6fa3e126c57d3d1bbfaf01625c3af0c15da44e4", + .hash = "12208fcae95a6d3bc80301bfbabe9f937cf299188f44bed100f61e39437d8fc4a49a", }, .@"microzig-core" = .{ .url = "https://public.devspace.random-projects.net/microzig-core.tar.gz", - .hash = "1220a37d914f0585bbaeba2bc4d4d15586bef310a6af340af87f0e13fde0b4ddfb1a", + .hash = "122085d8c30906f461a3aecb54eb0dadb644c25724b0eb2d3fc89f1f4c3a8d411be2", }, .@"microzig-bsp-nxp" = .{ .url = "https://public.devspace.random-projects.net/board-support/nxp/lpc.tar.gz", - .hash = "122040dc9467f6dac90a1376fff25350b2a5abd291904db7bea48a78db4f6e6dff13", + .hash = "12201530a2d4d2751a5bc93720d3a3d6eab0349cc271004102bcc470beffb02c7e84", }, .@"microzig-bsp-rp2040" = .{ .url = "https://public.devspace.random-projects.net/board-support/raspberrypi/rp2040.tar.gz", - .hash = "1220142a13e590252deb7667569bdd3f6147c5b461f6b0343a825079a7dd3a24dea9", + .hash = "1220817e39ac34923bae65047afc344706c11e7dd054efee3ca31ff78adc78a4e0f6", }, }, } \ No newline at end of file diff --git a/tools/bundle.py b/tools/bundle.py index e00cda0..eebb215 100755 --- a/tools/bundle.py +++ b/tools/bundle.py @@ -145,7 +145,7 @@ def execute_raw(*args,hide_stderr = False,**kwargs): sys.stderr.buffer.write(res.stderr) if res.returncode != 0: sys.stderr.write(f"command {' '.join(args)} failed with exit code {res.returncode}") - res.check_returncode() + sys.exit(res.returncode) return res def execute(*args,**kwargs): diff --git a/tools/extract-bsp-info.zig b/tools/extract-bsp-info.zig index 4c2b260..a157be7 100644 --- a/tools/extract-bsp-info.zig +++ b/tools/extract-bsp-info.zig @@ -7,6 +7,11 @@ const std = @import("std"); const bsp = @import("bsp"); const microzig = @import("microzig-build"); +// Fake build_runner.zig api: +pub const dependencies = struct { + pub const imports = struct {}; +}; + const JsonTarget = struct { id: []const u8,