Fixes build script enough to make next-gen example build.

wch-ch32v003
Felix "xq" Queißner 8 months ago
parent 99e8d09cf0
commit 4480b7c17a

@ -137,15 +137,15 @@ const chip = .{
}; };
/// Returns a configuration function that will add the provided `BootROM` to the firmware. /// 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 { const T = struct {
fn configure(host_build: *std.Build, fw: *microzig.Firmware) void { fn configure(env: *microzig.BuildEnvironment, fw: *microzig.Firmware) void {
const bootrom_file = getBootrom(host_build, bootrom); const bootrom_file = getBootrom(env, bootrom);
// HACK: Inject the file as a dependency to MicroZig.board // HACK: Inject the file as a dependency to MicroZig.board
fw.modules.board.?.dependencies.put( fw.modules.board.?.dependencies.put(
"bootloader", "bootloader",
host_build.createModule(.{ env.host_build.createModule(.{
.source_file = bootrom_file.bin, .source_file = bootrom_file.bin,
}), }),
) catch @panic("oom"); ) catch @panic("oom");
@ -161,7 +161,7 @@ pub const Stage2Bootloader = struct {
elf: ?std.Build.LazyPath, 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) { const rom_exe = switch (rom) {
.artifact => |artifact| artifact, .artifact => |artifact| artifact,
.blob => |blob| return Stage2Bootloader{ .blob => |blob| return Stage2Bootloader{
@ -170,13 +170,13 @@ pub fn getBootrom(b: *std.Build, rom: BootROM) Stage2Bootloader {
}, },
else => blk: { else => blk: {
var target = @as(microzig.CpuModel, chip.cpu).getDescriptor().target; var target = env.getCpuDescriptor(chip.cpu).target;
target.abi = .eabi; 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(.{ const rom_exe = env.host_build.addExecutable(.{
.name = b.fmt("stage2-{s}", .{@tagName(rom)}), .name = env.host_build.fmt("stage2-{s}", .{@tagName(rom)}),
.optimize = .ReleaseSmall, .optimize = .ReleaseSmall,
.target = target, .target = target,
.root_source_file = null, .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(), .{ const rom_objcopy = env.host_build.addObjCopy(rom_exe.getEmittedBin(), .{
.basename = b.fmt("{s}.bin", .{@tagName(rom)}), .basename = env.host_build.fmt("{s}.bin", .{@tagName(rom)}),
.format = .bin, .format = .bin,
}); });

@ -5,10 +5,64 @@
const std = @import("std"); const std = @import("std");
const uf2 = @import("uf2"); 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 // // 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 BoardSupportPackageDefinition = struct {
pub const TargetDefinition = struct { pub const TargetDefinition = struct {
id: []const u8, // full "uri" id: []const u8, // full "uri"
@ -109,21 +163,14 @@ const ImportedBSP = struct {
}; };
fn get_declared_bsps() []const ImportedBSP { 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 = &.{}; var bsps: []const ImportedBSP = &.{};
inline for (@typeInfo(deps.imports).Struct.decls) |decl| { inline for (zig_deps.names, zig_deps.modules) |name, maybe_bsp| {
if (comptime std.mem.indexOfScalar(u8, decl.name, '.') == null) { if (comptime std.mem.indexOfScalar(u8, name, '.') == null) {
const maybe_bsp = @field(deps.imports, decl.name);
if (@hasDecl(maybe_bsp, "microzig_board_support")) { if (@hasDecl(maybe_bsp, "microzig_board_support")) {
const bsp = @field(maybe_bsp, "microzig_board_support"); const bsp = @field(maybe_bsp, "microzig_board_support");
if (@TypeOf(bsp) == BoardSupportPackageDefinition) { if (@TypeOf(bsp) == BoardSupportPackageDefinition) {
bsps = bsps ++ [_]ImportedBSP{.{ bsps = bsps ++ [_]ImportedBSP{.{
.import_name = decl.name, .import_name = name,
.bsp = bsp, .bsp = bsp,
}}; }};
} }
@ -139,24 +186,72 @@ pub const EnvironmentInfo = struct {
/// package name of the core package (optional) /// package name of the core package (optional)
core: []const u8 = "microzig-core", 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 { pub fn createBuildEnvironment(b: *std.Build, comptime info: EnvironmentInfo) *BuildEnvironment {
const available_bsps = comptime get_declared_bsps(); 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"); const be = b.allocator.create(BuildEnvironment) catch @panic("out of memory");
be.* = BuildEnvironment{ be.* = BuildEnvironment{
.host_build = b, .host_build = b,
.self = undefined, .self = undefined,
.microzig_core = 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 = .{}, .targets = .{},
.self_pkg_name = comptime info.self,
.core_pkg_name = comptime info.core,
.cpus = &core_module.cpus,
}; };
be.self = b.dependency(info.self, .{}); be.self = b.dependency(info.self, .{});
be.microzig_core = b.dependency(info.core, .{}); 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{ bsp.* = BoardSupportPackage{
.name = def.import_name, .name = def.import_name,
.dep = b.dependency(def.import_name, .{}), .dep = b.dependency(def.import_name, .{}),
@ -184,14 +279,28 @@ pub const BuildEnvironment = struct {
microzig_core: *std.Build.Dependency, microzig_core: *std.Build.Dependency,
self_pkg_name: []const u8,
core_pkg_name: []const u8,
board_support_packages: []BoardSupportPackage, board_support_packages: []BoardSupportPackage,
targets: std.StringArrayHashMapUnmanaged(Target), 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 { pub fn findTarget(env: *const BuildEnvironment, name: []const u8) ?*const Target {
return env.targets.getPtr(name); 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. /// Declares a new MicroZig firmware file.
pub fn addFirmware( pub fn addFirmware(
/// The MicroZig instance that should be used to create the firmware. /// 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 micro_build = env.self.builder;
const chip = &options.target.chip; 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_hal = options.hal orelse options.target.hal;
const maybe_board = options.board orelse options.target.board; const maybe_board = options.board orelse options.target.board;
@ -259,7 +368,7 @@ pub const BuildEnvironment = struct {
.optimize = options.optimize, .optimize = options.optimize,
.target = cpu.target, .target = cpu.target,
.linkage = .static, .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, .target = options.target,
.output_files = Firmware.OutputFileMap.init(host_build.allocator), .output_files = Firmware.OutputFileMap.init(host_build.allocator),
@ -268,7 +377,7 @@ pub const BuildEnvironment = struct {
.modules = .{ .modules = .{
.microzig = micro_build.createModule(.{ .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 = &.{ .dependencies = &.{
.{ .{
.name = "config", .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.modules.microzig.dependencies.put("umm", umm) catch @panic("out of memory");
fw.artifact.addModule("app", fw.modules.app); fw.artifact.addModule("app", fw.modules.app);
@ -344,7 +453,7 @@ pub const BuildEnvironment = struct {
switch (linker_script) { switch (linker_script) {
.generated => { .generated => {
fw.artifact.setLinkerScript( 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| { if (options.target.configure) |configure| {
configure(host_build, fw); configure(fw.env, fw);
} }
return fw; return fw;
@ -404,98 +513,145 @@ pub const BuildEnvironment = struct {
fn dependency(env: *BuildEnvironment, name: []const u8, args: anytype) *std.Build.Dependency { fn dependency(env: *BuildEnvironment, name: []const u8, args: anytype) *std.Build.Dependency {
return env.self.builder.dependency(name, args); return env.self.builder.dependency(name, args);
} }
};
//////////////////////////////////////// fn generateLinkerScript(env: *BuildEnvironment, chip: Chip) !std.Build.LazyPath {
// MicroZig Gen 2 Interface // const cpu = env.getCpuDescriptor(chip.cpu);
////////////////////////////////////////
fn root() []const u8 { var contents = std.ArrayList(u8).init(env.host_build.allocator);
return comptime (std.fs.path.dirname(@src().file) orelse "."); const writer = contents.writer();
} try writer.print(
const build_root = root(); \\/*
\\ * 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,
});
const MicroZig = @This(); 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
b: *std.Build, switch (region.kind) {
self: *std.Build.Dependency, .flash => {
try writer.print(" flash{d} (rx!w)", .{counters[0]});
counters[0] += 1;
},
/// Creates a new instance of the MicroZig build support. .ram => {
/// try writer.print(" ram{d} (rw!x)", .{counters[1]});
/// This is necessary as we need to keep track of some internal state to prevent counters[1] += 1;
/// 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;
}
/// This build script validates usage patterns we expect from MicroZig .io => {
pub fn build(b: *std.Build) !void { try writer.print(" io{d} (rw!x)", .{counters[2]});
const uf2_dep = b.dependency("uf2", .{}); counters[2] += 1;
},
const build_test = b.addTest(.{ .reserved => {
.root_source_file = .{ .path = "build.zig" }, try writer.print(" reserved{d} (rw!x)", .{counters[3]});
}); counters[3] += 1;
},
build_test.addAnonymousModule("uf2", .{ .private => |custom| {
.source_file = .{ .cwd_relative = uf2_dep.builder.pathFromRoot("build.zig") }, 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");
const install_docs = b.addInstallDirectory(.{ if (!custom.readable or !custom.writeable or !custom.executable) {
.source_dir = build_test.getEmittedDocs(), try writer.writeAll("!");
.install_dir = .prefix, if (!custom.readable) try writer.writeAll("r");
.install_subdir = "docs", 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 });
}
}
b.getInstallStep().dependOn(&install_docs.step); 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 backings = @import("test/backings.zig"); try writer.writeAll(
// const optimize = b.standardOptimizeOption(.{}); \\ .data :
\\ {
// const minimal = addEmbeddedExecutable(b, .{ \\ microzig_data_start = .;
// .name = "minimal", \\ *(.rodata*)
// .source_file = .{ \\ *(.data*)
// .path = comptime root_dir() ++ "/test/programs/minimal.zig", \\ microzig_data_end = .;
// }, \\ } > ram0 AT> flash0
// .backing = backings.minimal, \\
// .optimize = optimize, \\ .bss (NOLOAD) :
// }); \\ {
\\ microzig_bss_start = .;
// const has_hal = addEmbeddedExecutable(b, .{ \\ *(.bss*)
// .name = "has_hal", \\ microzig_bss_end = .;
// .source_file = .{ \\ } > ram0
// .path = comptime root_dir() ++ "/test/programs/has_hal.zig", \\
// }, \\ microzig_data_load_start = LOADADDR(.data);
// .backing = backings.has_hal, \\
// .optimize = optimize, );
// }); }
try writer.writeAll("}\n");
// const has_board = addEmbeddedExecutable(b, .{
// .name = "has_board", // TODO: Assert that the flash can actually hold all data!
// .source_file = .{ // try writer.writeAll(
// .path = comptime root_dir() ++ "/test/programs/has_board.zig", // \\
// }, // \\ ASSERT( (SIZEOF(.text) + SIZEOF(.data) > LENGTH(flash0)), "Error: .text + .data is too large for flash!" );
// .backing = backings.has_board, // \\
// .optimize = optimize, // );
// });
const write = env.host_build.addWriteFiles();
// const core_tests = b.addTest(.{
// .root_source_file = .{ return write.add("linker.ld", contents.items);
// .path = comptime root_dir() ++ "/src/core.zig", }
// }, };
// .optimize = optimize,
// }); ////////////////////////////////////////
// MicroZig Gen 2 Interface //
// const test_step = b.step("test", "build test programs"); ////////////////////////////////////////
// test_step.dependOn(&minimal.inner.step);
// test_step.dependOn(&has_hal.inner.step); fn root() []const u8 {
// test_step.dependOn(&has_board.inner.step); return comptime (std.fs.path.dirname(@src().file) orelse ".");
// test_step.dependOn(&b.addRunArtifact(core_tests).step);
} }
const build_root = root();
const MicroZig = @This();
/// The resulting binary format for the firmware file. /// The resulting binary format for the firmware file.
/// A lot of embedded systems don't use plain ELF files, thus we provide means /// 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_m3,
cortex_m4, cortex_m4,
riscv32_imac, riscv32_imac,
custom: *const Cpu, 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. /// A cpu descriptor.
pub const Cpu = struct { pub const Cpu = struct {
/// Display name of the CPU. /// 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. /// (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. /// 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. /// (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, 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 { fn buildConfigError(b: *std.Build, comptime fmt: []const u8, args: anytype) noreturn {
const msg = b.fmt(fmt, args); const msg = b.fmt(fmt, args);
@panic(msg); @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);
}

@ -13,70 +13,10 @@ const build_root = root();
/// This build script validates usage patterns we expect from MicroZig /// This build script validates usage patterns we expect from MicroZig
pub fn build(b: *std.Build) !void { pub fn build(b: *std.Build) !void {
_ = b; _ = 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 cpus = microbuild.CpuArray.init(.{
pub const avr5 = microbuild.Cpu{ .avr5 = microbuild.Cpu{
.name = "AVR5", .name = "AVR5",
.source_file = .{ .path = build_root ++ "/src/cpus/avr5.zig" }, .source_file = .{ .path = build_root ++ "/src/cpus/avr5.zig" },
.target = std.zig.CrossTarget{ .target = std.zig.CrossTarget{
@ -85,9 +25,9 @@ pub const cpus = struct {
.os_tag = .freestanding, .os_tag = .freestanding,
.abi = .eabi, .abi = .eabi,
}, },
}; },
pub const cortex_m0 = microbuild.Cpu{ .cortex_m0 = microbuild.Cpu{
.name = "ARM Cortex-M0", .name = "ARM Cortex-M0",
.source_file = .{ .path = build_root ++ "/src/cpus/cortex-m.zig" }, .source_file = .{ .path = build_root ++ "/src/cpus/cortex-m.zig" },
.target = std.zig.CrossTarget{ .target = std.zig.CrossTarget{
@ -96,9 +36,9 @@ pub const cpus = struct {
.os_tag = .freestanding, .os_tag = .freestanding,
.abi = .eabi, .abi = .eabi,
}, },
}; },
pub const cortex_m0plus = microbuild.Cpu{ .cortex_m0plus = microbuild.Cpu{
.name = "ARM Cortex-M0+", .name = "ARM Cortex-M0+",
.source_file = .{ .path = build_root ++ "/src/cpus/cortex-m.zig" }, .source_file = .{ .path = build_root ++ "/src/cpus/cortex-m.zig" },
.target = std.zig.CrossTarget{ .target = std.zig.CrossTarget{
@ -107,9 +47,9 @@ pub const cpus = struct {
.os_tag = .freestanding, .os_tag = .freestanding,
.abi = .eabi, .abi = .eabi,
}, },
}; },
pub const cortex_m3 = microbuild.Cpu{ .cortex_m3 = microbuild.Cpu{
.name = "ARM Cortex-M3", .name = "ARM Cortex-M3",
.source_file = .{ .path = build_root ++ "/src/cpus/cortex-m.zig" }, .source_file = .{ .path = build_root ++ "/src/cpus/cortex-m.zig" },
.target = std.zig.CrossTarget{ .target = std.zig.CrossTarget{
@ -118,9 +58,9 @@ pub const cpus = struct {
.os_tag = .freestanding, .os_tag = .freestanding,
.abi = .eabi, .abi = .eabi,
}, },
}; },
pub const cortex_m4 = microbuild.Cpu{ .cortex_m4 = microbuild.Cpu{
.name = "ARM Cortex-M4", .name = "ARM Cortex-M4",
.source_file = .{ .path = build_root ++ "/src/cpus/cortex-m.zig" }, .source_file = .{ .path = build_root ++ "/src/cpus/cortex-m.zig" },
.target = std.zig.CrossTarget{ .target = std.zig.CrossTarget{
@ -129,9 +69,9 @@ pub const cpus = struct {
.os_tag = .freestanding, .os_tag = .freestanding,
.abi = .eabi, .abi = .eabi,
}, },
}; },
pub const riscv32_imac = microbuild.Cpu{ .riscv32_imac = microbuild.Cpu{
.name = "RISC-V 32-bit", .name = "RISC-V 32-bit",
.source_file = .{ .path = build_root ++ "/src/cpus/riscv32.zig" }, .source_file = .{ .path = build_root ++ "/src/cpus/riscv32.zig" },
.target = std.zig.CrossTarget{ .target = std.zig.CrossTarget{
@ -140,5 +80,7 @@ pub const cpus = struct {
.os_tag = .freestanding, .os_tag = .freestanding,
.abi = .none, .abi = .none,
}, },
}; },
};
.custom = undefined,
});

@ -4,19 +4,19 @@
.dependencies = .{ .dependencies = .{
.microzig = .{ .microzig = .{
.url = "https://public.devspace.random-projects.net/microzig-build.tar.gz", .url = "https://public.devspace.random-projects.net/microzig-build.tar.gz",
.hash = "1220c87cc608598bdb4ae5ed6436c6fa3e126c57d3d1bbfaf01625c3af0c15da44e4", .hash = "12208fcae95a6d3bc80301bfbabe9f937cf299188f44bed100f61e39437d8fc4a49a",
}, },
.@"microzig-core" = .{ .@"microzig-core" = .{
.url = "https://public.devspace.random-projects.net/microzig-core.tar.gz", .url = "https://public.devspace.random-projects.net/microzig-core.tar.gz",
.hash = "1220a37d914f0585bbaeba2bc4d4d15586bef310a6af340af87f0e13fde0b4ddfb1a", .hash = "122085d8c30906f461a3aecb54eb0dadb644c25724b0eb2d3fc89f1f4c3a8d411be2",
}, },
.@"microzig-bsp-nxp" = .{ .@"microzig-bsp-nxp" = .{
.url = "https://public.devspace.random-projects.net/board-support/nxp/lpc.tar.gz", .url = "https://public.devspace.random-projects.net/board-support/nxp/lpc.tar.gz",
.hash = "122040dc9467f6dac90a1376fff25350b2a5abd291904db7bea48a78db4f6e6dff13", .hash = "12201530a2d4d2751a5bc93720d3a3d6eab0349cc271004102bcc470beffb02c7e84",
}, },
.@"microzig-bsp-rp2040" = .{ .@"microzig-bsp-rp2040" = .{
.url = "https://public.devspace.random-projects.net/board-support/raspberrypi/rp2040.tar.gz", .url = "https://public.devspace.random-projects.net/board-support/raspberrypi/rp2040.tar.gz",
.hash = "1220142a13e590252deb7667569bdd3f6147c5b461f6b0343a825079a7dd3a24dea9", .hash = "1220817e39ac34923bae65047afc344706c11e7dd054efee3ca31ff78adc78a4e0f6",
}, },
}, },
} }

@ -145,7 +145,7 @@ def execute_raw(*args,hide_stderr = False,**kwargs):
sys.stderr.buffer.write(res.stderr) sys.stderr.buffer.write(res.stderr)
if res.returncode != 0: if res.returncode != 0:
sys.stderr.write(f"command {' '.join(args)} failed with exit code {res.returncode}") sys.stderr.write(f"command {' '.join(args)} failed with exit code {res.returncode}")
res.check_returncode() sys.exit(res.returncode)
return res return res
def execute(*args,**kwargs): def execute(*args,**kwargs):

@ -7,6 +7,11 @@ const std = @import("std");
const bsp = @import("bsp"); const bsp = @import("bsp");
const microzig = @import("microzig-build"); const microzig = @import("microzig-build");
// Fake build_runner.zig api:
pub const dependencies = struct {
pub const imports = struct {};
};
const JsonTarget = struct { const JsonTarget = struct {
id: []const u8, id: []const u8,

Loading…
Cancel
Save