Adds auto-discovery of BSPs.

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

@ -1,4 +1,7 @@
const std = @import("std");
const MicroZig = @import("microzig-build");
pub const microzig_board_support = MicroZig.registerBoardSupport(@This());
fn path(comptime suffix: []const u8) std.Build.LazyPath {
return .{
@ -26,7 +29,7 @@ const hal = .{
};
pub const chips = struct {
pub const esp32_c3 = .{
pub const esp32_c3 = MicroZig.Target{
.preferred_format = .bin, // TODO: Exchange FLAT format with .esp format
.chip = .{
.name = "ESP32-C3",

@ -1,4 +1,7 @@
const std = @import("std");
const MicroZig = @import("microzig-build");
pub const microzig_board_support = MicroZig.registerBoardSupport(@This());
fn path(comptime suffix: []const u8) std.Build.LazyPath {
return .{
@ -11,7 +14,7 @@ const hal = .{
};
pub const chips = struct {
pub const gd32vf103xb = .{
pub const gd32vf103xb = MicroZig.Target{
.preferred_format = .elf,
.chip = .{
.name = "GD32VF103",
@ -27,7 +30,7 @@ pub const chips = struct {
.hal = hal,
};
pub const gd32vf103x8 = .{
pub const gd32vf103x8 = MicroZig.Target{
.preferred_format = .elf,
.chip = .{
.name = "GD32VF103",
@ -46,7 +49,7 @@ pub const chips = struct {
pub const boards = struct {
pub const sipeed = struct {
pub const longan_nano = .{
pub const longan_nano = MicroZig.Target{
.preferred_format = .elf,
.chip = chips.gd32vf103xb.chip,
.hal = hal,

@ -1,4 +1,7 @@
const std = @import("std");
const MicroZig = @import("microzig-build");
pub const microzig_board_support = MicroZig.registerBoardSupport(@This());
pub fn build(b: *std.Build) void {
_ = b;
@ -27,7 +30,7 @@ pub const chip_atsamd51j19 = .{
};
pub const chips = struct {
pub const atsamd51j19 = .{
pub const atsamd51j19 = MicroZig.Target{
.preferred_format = .elf,
.chip = chip_atsamd51j19,
};

@ -1,4 +1,7 @@
const std = @import("std");
const MicroZig = @import("microzig-build");
pub const microzig_board_support = MicroZig.registerBoardSupport(@This());
fn path(comptime suffix: []const u8) std.Build.LazyPath {
return .{
@ -11,7 +14,7 @@ const hal = .{
};
pub const chips = struct {
pub const atmega328p = .{
pub const atmega328p = MicroZig.Target{
.preferred_format = .hex,
.chip = .{
.name = "ATmega328P",
@ -31,7 +34,7 @@ pub const chips = struct {
pub const boards = struct {
pub const arduino = struct {
pub const nano = .{
pub const nano = MicroZig.Target{
.preferred_format = .hex,
.chip = chips.atmega328p.chip,
.hal = hal,
@ -42,7 +45,7 @@ pub const boards = struct {
},
};
pub const uno_rev3 = .{
pub const uno_rev3 = MicroZig.Target{
.preferred_format = .hex,
.chip = chips.atmega328p.chip,
.hal = hal,

@ -1,6 +1,8 @@
const std = @import("std");
const MicroZig = @import("microzig-build");
pub const microzig_board_support = MicroZig.registerBoardSupport(@This());
fn path(comptime suffix: []const u8) std.Build.LazyPath {
return .{
.cwd_relative = comptime ((std.fs.path.dirname(@src().file) orelse ".") ++ suffix),

@ -1,6 +1,8 @@
const std = @import("std");
const MicroZig = @import("microzig-build");
pub const microzig_board_support = MicroZig.registerBoardSupport(@This());
fn path(comptime suffix: []const u8) std.Build.LazyPath {
return .{
.cwd_relative = comptime ((std.fs.path.dirname(@src().file) orelse ".") ++ suffix),

@ -1,6 +1,8 @@
const std = @import("std");
const microzig = @import("microzig-build");
pub const microzig_board_support = microzig.registerBoardSupport(@This());
fn root() []const u8 {
return comptime (std.fs.path.dirname(@src().file) orelse ".");
}

@ -1,5 +1,7 @@
const std = @import("std");
const microzig = @import("microzig-build");
const MicroZig = @import("microzig-build");
pub const microzig_board_support = MicroZig.registerBoardSupport(@This());
fn root() []const u8 {
return comptime (std.fs.path.dirname(@src().file) orelse ".");
@ -18,7 +20,7 @@ pub fn build(b: *std.Build) !void {
}
pub const chips = struct {
pub const stm32f103x8 = .{
pub const stm32f103x8 = MicroZig.Target{
.preferred_format = .elf,
.chip = .{
.name = "STM32F103",
@ -36,7 +38,7 @@ pub const chips = struct {
},
};
pub const stm32f303vc = .{
pub const stm32f303vc = MicroZig.Target{
.preferred_format = .elf,
.chip = .{
.name = "STM32F303",
@ -51,7 +53,7 @@ pub const chips = struct {
},
};
pub const stm32f407vg = .{
pub const stm32f407vg = MicroZig.Target{
.preferred_format = .elf,
.chip = .{
.name = "STM32F407",
@ -67,7 +69,7 @@ pub const chips = struct {
},
};
pub const stm32f429zit6u = .{
pub const stm32f429zit6u = MicroZig.Target{
.preferred_format = .elf,
.chip = .{
.name = "STM32F429",
@ -85,8 +87,8 @@ pub const chips = struct {
// All STM32L0x1 series MCUs differ only in memory size. So we create a comptime function
// to generate all MCU variants as per https://www.st.com/en/microcontrollers-microprocessors/stm32l0x1.html
fn stm32l0x1(comptime rom_size: u64, comptime ram_size: u64) microzig.Target {
return microzig.Target{
fn stm32l0x1(comptime rom_size: u64, comptime ram_size: u64) MicroZig.Target {
return MicroZig.Target{
.preferred_format = .elf,
.chip = .{
.name = "STM32L0x1",
@ -123,8 +125,8 @@ pub const chips = struct {
// All STM32L0x2 series MCUs differ only in memory size. So we create a comptime function
// to generate all MCU variants as per https://www.st.com/en/microcontrollers-microprocessors/stm32l0x2.html
fn stm32l0x2(comptime rom_size: u64, comptime ram_size: u64) microzig.Target {
return microzig.Target{
fn stm32l0x2(comptime rom_size: u64, comptime ram_size: u64) MicroZig.Target {
return MicroZig.Target{
.preferred_format = .elf,
.chip = .{
.name = "STM32L0x2",
@ -154,8 +156,8 @@ pub const chips = struct {
// All STM32L0x2 series MCUs differ only in memory size. So we create a comptime function
// to generate all MCU variants as per https://www.st.com/en/microcontrollers-microprocessors/stm32l0x3.html
fn stm32l0x3(comptime rom_size: u64, comptime ram_size: u64) microzig.Target {
return microzig.Target{
fn stm32l0x3(comptime rom_size: u64, comptime ram_size: u64) MicroZig.Target {
return MicroZig.Target{
.preferred_format = .elf,
.chip = .{
.name = "STM32L0x3",
@ -187,7 +189,7 @@ pub const chips = struct {
};
pub const boards = struct {
pub const stm32f3discovery = .{
pub const stm32f3discovery = MicroZig.Target{
.preferred_format = .elf,
.chip = chips.stm32f303vc.chip,
.board = .{
@ -196,7 +198,7 @@ pub const boards = struct {
},
};
pub const stm32f4discovery = .{
pub const stm32f4discovery = MicroZig.Target{
.preferred_format = .elf,
.chip = chips.stm32f407vg.chip,
.board = .{
@ -205,7 +207,7 @@ pub const boards = struct {
},
};
pub const stm3240geval = .{
pub const stm3240geval = MicroZig.Target{
.preferred_format = .elf,
.chip = chips.stm32f407vg.chip,
.board = .{
@ -214,7 +216,7 @@ pub const boards = struct {
},
};
pub const stm32f429idiscovery = .{
pub const stm32f429idiscovery = MicroZig.Target{
.preferred_format = .elf,
.chip = chips.stm32f429zit6u.chip,
.board = .{

@ -9,103 +9,168 @@ const uf2 = @import("uf2");
// MicroZig Gen 3 Interface //
////////////////////////////////////////
pub const EnvironmentInfo = struct {
/// include package names of your board support packages here:
board_support: []const []const u8,
/// package name of the build package (optional)
self: []const u8 = "microzig",
/// package name of the core package (optional)
core: []const u8 = "microzig-core",
};
pub fn createBuildEnvironment(b: *std.Build, comptime info: EnvironmentInfo) *BuildEnvironment {
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, info.board_support.len) catch @panic("out of memory"),
.targets = .{},
pub const BoardSupportPackageDefinition = struct {
pub const TargetDefinition = struct {
id: []const u8, // full "uri"
target: Target,
};
be.self = b.dependency(info.self, .{});
be.microzig_core = b.dependency(info.core, .{});
bsp_root: type,
targets: []const TargetDefinition,
for (be.board_support_packages, info.board_support) |*out, in| {
out.* = BoardSupportPackage{
.name = in,
.dep = b.dependency(in, .{}),
};
}
// Fetch and collect all supported targets:
inline for (info.board_support) |bsp_name| {
// Keep in sync with the logic from Build.zig:dependency
const build_runner = @import("root");
const deps = build_runner.dependencies;
const bsp_root = @field(deps.imports, bsp_name);
fn init(comptime bsp_root: type) BoardSupportPackageDefinition {
var targets: []const TargetDefinition = &.{};
if (@hasDecl(bsp_root, "chips")) {
fetch_microzig_targets("chip:", bsp_root.chips, bsp_name, be);
targets = targets ++ construct_target_database("chip:", bsp_root.chips);
}
if (@hasDecl(bsp_root, "boards")) {
fetch_microzig_targets("board:", bsp_root.boards, bsp_name, be);
targets = targets ++ construct_target_database("board:", bsp_root.boards);
}
if (targets.len == 0) {
@compileError("Board support package contains not a single target. Please add at least one target!");
}
return be;
return BoardSupportPackageDefinition{
.bsp_root = bsp_root,
.targets = targets,
};
}
fn fetch_microzig_targets(comptime prefix: []const u8, comptime namespace: type, comptime bsp_name: []const u8, be: *BuildEnvironment) void {
fn construct_target_database(comptime prefix: []const u8, comptime namespace: type) []const TargetDefinition {
var list: []const TargetDefinition = &.{};
inline for (@typeInfo(namespace).Struct.decls) |decl_info| {
const decl = @field(namespace, decl_info.name);
const T = @TypeOf(decl);
const name = comptime prefix ++ decl_info.name; // board:vendor/name
const full_name = comptime name ++ "#" ++ bsp_name; // board:vendor/name#bsp-package-name
if (T == Target) {
const target: Target = decl;
be.targets.put(be.host_build.allocator, name, target) catch @panic("out of memory");
be.targets.put(be.host_build.allocator, full_name, target) catch @panic("out of memory");
list = list ++ &[_]TargetDefinition{.{
.id = name,
.target = target,
}};
// be.targets.put(be.host_build.allocator, name, target) catch @panic("out of memory");
} else {
const ok = blk: {
if (comptime T != type) {
// @compileLog(full_name, "check 1:", T, decl);
break :blk false;
if (T != type) {
@compileError(std.fmt.comptimePrint("Declaration {s} is neither a MicroZig.Target nor a namespace. Expected declaration to be a 'type', found {s}.", .{
name,
@typeName(T),
}));
}
const ti = @typeInfo(decl);
if (comptime ti != .Struct) {
// @compileLog(full_name, "check 2:", ti);
break :blk false;
if (ti != .Struct) {
@compileError(std.fmt.comptimePrint("Declaration {s} is neither a MicroZig.Target nor a namespace. Expected declaration to be a 'struct', found {s}.", .{
name,
@tagName(ti),
}));
}
if (comptime ti.Struct.fields.len > 0) {
// @compileLog(full_name, "check 3:", ti.Struct);
// @compileLog(full_name, "check 3:", ti.Struct.fields);
break :blk false;
if (ti.Struct.fields.len > 0) {
@compileError(std.fmt.comptimePrint("Declaration {s} is neither a MicroZig.Target nor a namespace. Expected declaration to have no fields, but found {} fields.", .{
name,
ti.Struct.fields.len,
}));
}
fetch_microzig_targets(
const sublist = construct_target_database(
comptime name ++ "/",
decl,
bsp_name,
be,
);
break :blk true;
list = list ++ sublist;
}
}
return list;
}
};
if (!ok) {
std.debug.print("Bad BSP: {s} is neither namespace nor a microzig.Target\n", .{ prefix, full_name });
/// Validates a board support package and returns a registration type that can be used
/// with MicroZig automatic BSP discovery.
///
/// Store the return value into a public constant named "" at the root of your build script:
///
/// pub const microzig_board_support = microzig.registerBoardSupport(@This());
///
pub fn registerBoardSupport(comptime bsp_root: type) BoardSupportPackageDefinition {
return BoardSupportPackageDefinition.init(bsp_root);
}
const ImportedBSP = struct {
import_name: []const u8,
bsp: BoardSupportPackageDefinition,
};
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);
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,
.bsp = bsp,
}};
}
}
}
}
return bsps;
}
pub const EnvironmentInfo = struct {
/// package name of the build package (optional)
self: []const u8 = "microzig",
/// package name of the core package (optional)
core: []const u8 = "microzig-core",
};
pub fn createBuildEnvironment(b: *std.Build, comptime info: EnvironmentInfo) *BuildEnvironment {
const available_bsps = comptime get_declared_bsps();
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"),
.targets = .{},
};
be.self = b.dependency(info.self, .{});
be.microzig_core = b.dependency(info.core, .{});
inline for (be.board_support_packages, available_bsps) |*bsp, def| {
bsp.* = BoardSupportPackage{
.name = def.import_name,
.dep = b.dependency(def.import_name, .{}),
};
for (def.bsp.targets) |tgt| {
const full_name = b.fmt("{s}#{s}", .{ tgt.id, def.import_name });
be.targets.put(be.host_build.allocator, tgt.id, tgt.target) catch @panic("out of memory");
be.targets.put(be.host_build.allocator, full_name, tgt.target) catch @panic("out of memory");
}
}
return be;
}
pub const BoardSupportPackage = struct {

@ -4,35 +4,12 @@
const std = @import("std");
const microbuild = @import("microzig-build");
// const uf2 = @import("uf2");
////////////////////////////////////////
// MicroZig Gen 2 Interface //
////////////////////////////////////////
fn root() []const u8 {
return comptime (std.fs.path.dirname(@src().file) orelse ".");
}
const build_root = root();
// const MicroZig = @This();
// b: *std.Build,
// self: *std.Build.Dependency,
// /// 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;
// }
/// This build script validates usage patterns we expect from MicroZig
pub fn build(b: *std.Build) !void {
_ = b;
@ -98,684 +75,6 @@ pub fn build(b: *std.Build) !void {
// test_step.dependOn(&b.addRunArtifact(core_tests).step);
}
// /// The resulting binary format for the firmware file.
// /// A lot of embedded systems don't use plain ELF files, thus we provide means
// /// to convert the resulting ELF into other common formats.
// pub const BinaryFormat = union(enum) {
// /// [Executable and Linkable Format](https://en.wikipedia.org/wiki/Executable_and_Linkable_Format), the standard output from the compiler.
// elf,
// /// A flat binary, contains only the loaded portions of the firmware with an unspecified base offset.
// bin,
// /// The [Intel HEX](https://en.wikipedia.org/wiki/Intel_HEX) format, contains
// /// an ASCII description of what memory to load where.
// hex,
// /// A [Device Firmware Upgrade](https://www.usb.org/sites/default/files/DFU_1.1.pdf) file.
// dfu,
// /// The [USB Flashing Format (UF2)](https://github.com/microsoft/uf2) designed by Microsoft.
// uf2: uf2.FamilyId,
// /// The [firmware format](https://docs.espressif.com/projects/esptool/en/latest/esp32/advanced-topics/firmware-image-format.html) used by the [esptool](https://github.com/espressif/esptool) bootloader.
// esp,
// /// Custom option for non-standard formats.
// custom: *Custom,
// /// Returns the standard extension for the resulting binary file.
// pub fn getExtension(format: BinaryFormat) []const u8 {
// return switch (format) {
// .elf => ".elf",
// .bin => ".bin",
// .hex => ".hex",
// .dfu => ".dfu",
// .uf2 => ".uf2",
// .esp => ".bin",
// .custom => |c| c.extension,
// };
// }
// pub const Custom = struct {
// /// The standard extension of the format.
// extension: []const u8,
// /// A function that will convert a given `elf` file into the custom output format.
// ///
// /// The `*Custom` format is passed so contextual information can be obtained by using
// /// `@fieldParentPtr` to provide access to tooling.
// convert: *const fn (*Custom, elf: std.Build.LazyPath) std.Build.LazyPath,
// };
// const Enum = std.meta.Tag(BinaryFormat);
// const Context = struct {
// pub fn hash(self: @This(), fmt: BinaryFormat) u32 {
// _ = self;
// var hasher = std.hash.XxHash32.init(0x1337_42_21);
// hasher.update(@tagName(fmt));
// switch (fmt) {
// .elf, .bin, .hex, .dfu, .esp => |val| {
// if (@TypeOf(val) != void) @compileError("Missing update: Context.hash now requires special care!");
// },
// .uf2 => |family_id| hasher.update(@tagName(family_id)),
// .custom => |custom| hasher.update(std.mem.asBytes(custom)),
// }
// return hasher.final();
// }
// pub fn eql(self: @This(), fmt_a: BinaryFormat, fmt_b: BinaryFormat, index: usize) bool {
// _ = self;
// _ = index;
// if (@as(BinaryFormat.Enum, fmt_a) != @as(BinaryFormat.Enum, fmt_b))
// return false;
// return switch (fmt_a) {
// .elf, .bin, .hex, .dfu, .esp => |val| {
// if (@TypeOf(val) != void) @compileError("Missing update: Context.eql now requires special care!");
// return true;
// },
// .uf2 => |a| (a == fmt_b.uf2),
// .custom => |a| (a == fmt_b.custom),
// };
// }
// };
// };
// /// The CPU model a target uses.
// ///
// /// The CPUs usually require special care on how to do interrupts, and getting an entry point.
// ///
// /// MicroZig officially only supports the CPUs listed here, but other CPUs might be provided
// /// via the `custom` field.
// pub const CpuModel = union(enum) {
// avr5,
// cortex_m0,
// cortex_m0plus,
// 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,
// };
// }
// };
// /// A cpu descriptor.
// pub const Cpu = struct {
// /// Display name of the CPU.
// name: []const u8,
// /// Source file providing startup code and memory initialization routines.
// source_file: std.build.LazyPath,
// /// The compiler target we use to compile all the code.
// target: std.zig.CrossTarget,
// };
// /// A descriptor for memory regions in a microcontroller.
// pub const MemoryRegion = struct {
// /// The type of the memory region for generating a proper linker script.
// kind: Kind,
// offset: u64,
// length: u64,
// pub const Kind = union(enum) {
// /// This is a (normally) immutable memory region where the code is stored.
// flash,
// /// This is a mutable memory region for data storage.
// ram,
// /// This is a memory region that maps MMIO devices.
// io,
// /// This is a memory region that exists, but is reserved and must not be used.
// reserved,
// /// This is a memory region used for internal linking tasks required by the board support package.
// private: PrivateRegion,
// };
// pub const PrivateRegion = struct {
// /// The name of the memory region. Will not have an automatic numeric counter and must be unique.
// name: []const u8,
// /// Is the memory region executable?
// executable: bool,
// /// Is the memory region readable?
// readable: bool,
// /// Is the memory region writable?
// writeable: bool,
// };
// };
// /// Defines a custom microcontroller.
// pub const Chip = struct {
// /// The display name of the controller.
// name: []const u8,
// /// (optional) link to the documentation/vendor page of the controller.
// url: ?[]const u8 = null,
// /// The cpu model this controller uses.
// cpu: CpuModel,
// /// The provider for register definitions.
// register_definition: union(enum) {
// /// Use `regz` to create a zig file from a JSON schema.
// json: std.Build.LazyPath,
// /// Use `regz` to create a json file from a SVD schema.
// svd: std.Build.LazyPath,
// /// Use `regz` to create a zig file from an ATDF schema.
// atdf: std.Build.LazyPath,
// /// Use the provided file directly as the chip file.
// zig: std.Build.LazyPath,
// },
// /// The memory regions that are present in this chip.
// memory_regions: []const MemoryRegion,
// };
// /// Defines a hardware abstraction layer.
// pub const HardwareAbstractionLayer = struct {
// /// Root source file for this HAL.
// source_file: std.Build.LazyPath,
// };
// /// Provides a description of a board.
// ///
// /// Boards provide additional information to a chip and HAL package.
// /// For example, they can list attached peripherials, external crystal frequencies,
// /// flash sizes, ...
// pub const BoardDefinition = struct {
// /// Display name of the board
// name: []const u8,
// /// (optional) link to the documentation/vendor page of the board.
// url: ?[]const u8 = null,
// /// Provides the root file for the board definition.
// source_file: std.Build.LazyPath,
// };
// /// The linker script used to link the firmware.
// pub const LinkerScript = union(enum) {
// /// Auto-generated linker script derived from the memory regions of the chip.
// generated,
// /// Externally defined linker script.
// source_file: std.build.LazyPath,
// };
// /// A compilation target for MicroZig. Provides information about the chip,
// /// hal, board and so on.
// ///
// /// This is used instead of `std.zig.CrossTarget` to define a MicroZig Firmware.
// pub const Target = struct {
// /// The preferred binary format of this MicroZig target. If `null`, the user must
// /// explicitly give the `.format` field during a call to `getEmittedBin()` or installation steps.
// preferred_format: ?BinaryFormat,
// /// The chip this target uses,
// chip: Chip,
// /// Usually, embedded projects are single-threaded and single-core applications. Platforms that
// /// support multiple CPUs should set this to `false`.
// single_threaded: bool = true,
// /// Determines whether the compiler_rt package is bundled with the application or not.
// /// This should always be true except for platforms where compiler_rt cannot be built right now.
// bundle_compiler_rt: bool = true,
// /// (optional) Provides a default hardware abstraction layer that is used.
// /// If `null`, no `microzig.hal` will be available.
// hal: ?HardwareAbstractionLayer = null,
// /// (optional) Provides description of external hardware and connected devices
// /// like oscillators and such.
// ///
// /// This structure isn't used by MicroZig itself, but can be utilized from the HAL
// /// if present.
// board: ?BoardDefinition = null,
// /// (optional) Provide a custom linker script for the hardware or define a custom generation.
// linker_script: LinkerScript = .generated,
// /// (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,
// /// (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,
// };
// /// Options to the `addFirmware` function.
// pub const FirmwareOptions = struct {
// /// The name of the firmware file.
// name: []const u8,
// /// The MicroZig target that the firmware is built for. Either a board or a chip.
// target: Target,
// /// The optimization level that should be used. Usually `ReleaseSmall` or `Debug` is a good choice.
// /// Also using `std.Build.standardOptimizeOption` is a good idea.
// optimize: std.builtin.OptimizeMode,
// /// The root source file for the application. This is your `src/main.zig` file.
// source_file: std.Build.LazyPath,
// // Overrides:
// /// If set, overrides the `single_threaded` property of the target.
// single_threaded: ?bool = null,
// /// If set, overrides the `bundle_compiler_rt` property of the target.
// bundle_compiler_rt: ?bool = null,
// /// If set, overrides the `hal` property of the target.
// hal: ?HardwareAbstractionLayer = null,
// /// If set, overrides the `board` property of the target.
// board: ?BoardDefinition = null,
// /// If set, overrides the `linker_script` property of the target.
// linker_script: ?LinkerScript = null,
// };
// /// Declares a new MicroZig firmware file.
// pub fn addFirmware(
// /// The MicroZig instance that should be used to create the firmware.
// mz: *MicroZig,
// /// The instance of the `build.zig` that is calling this function.
// host_build: *std.Build,
// /// Options that define how the firmware is built.
// options: FirmwareOptions,
// ) *Firmware {
// const micro_build = mz.self.builder;
// const chip = &options.target.chip;
// const cpu = chip.cpu.getDescriptor();
// const maybe_hal = options.hal orelse options.target.hal;
// const maybe_board = options.board orelse options.target.board;
// const linker_script = options.linker_script orelse options.target.linker_script;
// // TODO: let the user override which ram section to use the stack on,
// // for now just using the first ram section in the memory region list
// const first_ram = blk: {
// for (chip.memory_regions) |region| {
// if (region.kind == .ram)
// break :blk region;
// } else @panic("no ram memory region found for setting the end-of-stack address");
// };
// // On demand, generate chip definitions via regz:
// const chip_source = switch (chip.register_definition) {
// .json, .atdf, .svd => |file| blk: {
// const regz_exe = mz.dependency("regz", .{ .optimize = .ReleaseSafe }).artifact("regz");
// const regz_gen = host_build.addRunArtifact(regz_exe);
// regz_gen.addArg("--schema"); // Explicitly set schema type, one of: svd, atdf, json
// regz_gen.addArg(@tagName(chip.register_definition));
// regz_gen.addArg("--output_path"); // Write to a file
// const zig_file = regz_gen.addOutputFileArg("chip.zig");
// regz_gen.addFileArg(file);
// break :blk zig_file;
// },
// .zig => |src| src,
// };
// const config = host_build.addOptions();
// config.addOption(bool, "has_hal", (maybe_hal != null));
// config.addOption(bool, "has_board", (maybe_board != null));
// config.addOption(?[]const u8, "board_name", if (maybe_board) |brd| brd.name else null);
// config.addOption([]const u8, "chip_name", chip.name);
// config.addOption([]const u8, "cpu_name", chip.name);
// config.addOption(usize, "end_of_stack", first_ram.offset + first_ram.length);
// const fw: *Firmware = host_build.allocator.create(Firmware) catch @panic("out of memory");
// fw.* = Firmware{
// .mz = mz,
// .host_build = host_build,
// .artifact = host_build.addExecutable(.{
// .name = options.name,
// .optimize = options.optimize,
// .target = cpu.target,
// .linkage = .static,
// .root_source_file = .{ .cwd_relative = mz.self.builder.pathFromRoot("src/start.zig") },
// }),
// .target = options.target,
// .output_files = Firmware.OutputFileMap.init(host_build.allocator),
// .config = config,
// .modules = .{
// .microzig = micro_build.createModule(.{
// .source_file = .{ .cwd_relative = micro_build.pathFromRoot("src/microzig.zig") },
// .dependencies = &.{
// .{
// .name = "config",
// .module = micro_build.createModule(.{ .source_file = config.getSource() }),
// },
// },
// }),
// .cpu = undefined,
// .chip = undefined,
// .board = null,
// .hal = null,
// .app = undefined,
// },
// };
// errdefer fw.output_files.deinit();
// fw.modules.chip = micro_build.createModule(.{
// .source_file = chip_source,
// .dependencies = &.{
// .{ .name = "microzig", .module = fw.modules.microzig },
// },
// });
// fw.modules.microzig.dependencies.put("chip", fw.modules.chip) catch @panic("out of memory");
// fw.modules.cpu = micro_build.createModule(.{
// .source_file = cpu.source_file,
// .dependencies = &.{
// .{ .name = "microzig", .module = fw.modules.microzig },
// },
// });
// fw.modules.microzig.dependencies.put("cpu", fw.modules.cpu) catch @panic("out of memory");
// if (maybe_hal) |hal| {
// fw.modules.hal = micro_build.createModule(.{
// .source_file = hal.source_file,
// .dependencies = &.{
// .{ .name = "microzig", .module = fw.modules.microzig },
// },
// });
// fw.modules.microzig.dependencies.put("hal", fw.modules.hal.?) catch @panic("out of memory");
// }
// if (maybe_board) |brd| {
// fw.modules.board = micro_build.createModule(.{
// .source_file = brd.source_file,
// .dependencies = &.{
// .{ .name = "microzig", .module = fw.modules.microzig },
// },
// });
// fw.modules.microzig.dependencies.put("board", fw.modules.board.?) catch @panic("out of memory");
// }
// fw.modules.app = host_build.createModule(.{
// .source_file = options.source_file,
// .dependencies = &.{
// .{ .name = "microzig", .module = fw.modules.microzig },
// },
// });
// const umm = mz.dependency("umm-zig", .{}).module("umm");
// fw.modules.microzig.dependencies.put("umm", umm) catch @panic("out of memory");
// fw.artifact.addModule("app", fw.modules.app);
// fw.artifact.addModule("microzig", fw.modules.microzig);
// fw.artifact.strip = false; // we always want debug symbols, stripping brings us no benefit on embedded
// fw.artifact.single_threaded = options.single_threaded orelse fw.target.single_threaded;
// fw.artifact.bundle_compiler_rt = options.bundle_compiler_rt orelse fw.target.bundle_compiler_rt;
// switch (linker_script) {
// .generated => {
// fw.artifact.setLinkerScript(
// generateLinkerScript(host_build, chip.*) catch @panic("out of memory"),
// );
// },
// .source_file => |source| {
// fw.artifact.setLinkerScriptPath(source);
// },
// }
// if (options.target.configure) |configure| {
// configure(host_build, fw);
// }
// return fw;
// }
// /// Configuration options for firmware installation.
// pub const InstallFirmwareOptions = struct {
// /// Overrides the output format for the binary. If not set, the standard preferred file format for the firmware target is used.
// format: ?BinaryFormat = null,
// };
// /// Adds a new dependency to the `install` step that will install the `firmware` into the folder `$prefix/firmware`.
// pub fn installFirmware(
// /// The MicroZig instance that was used to create the firmware.
// mz: *MicroZig,
// /// The instance of the `build.zig` that should perform installation.
// b: *std.Build,
// /// The firmware that should be installed. Please make sure that this was created with the same `MicroZig` instance as `mz`.
// firmware: *Firmware,
// /// Optional configuration of the installation process. Pass `.{}` if you're not sure what to do here.
// options: InstallFirmwareOptions,
// ) void {
// std.debug.assert(mz == firmware.mz);
// const install_step = addInstallFirmware(mz, b, firmware, options);
// b.getInstallStep().dependOn(&install_step.step);
// }
// /// Creates a new `std.Build.Step.InstallFile` instance that will install the given firmware to `$prefix/firmware`.
// ///
// /// **NOTE:** This does not actually install the firmware yet. You have to add the returned step as a dependency to another step.
// /// If you want to just install the firmware, use `installFirmware` instead!
// pub fn addInstallFirmware(
// /// The MicroZig instance that was used to create the firmware.
// mz: *MicroZig,
// /// The instance of the `build.zig` that should perform installation.
// b: *std.Build,
// /// The firmware that should be installed. Please make sure that this was created with the same `MicroZig` instance as `mz`.
// firmware: *Firmware,
// /// Optional configuration of the installation process. Pass `.{}` if you're not sure what to do here.
// options: InstallFirmwareOptions,
// ) *std.Build.Step.InstallFile {
// const format = firmware.resolveFormat(options.format);
// const basename = b.fmt("{s}{s}", .{
// firmware.artifact.name,
// format.getExtension(),
// });
// _ = mz;
// return b.addInstallFileWithDir(firmware.getEmittedBin(format), .{ .custom = "firmware" }, basename);
// }
// /// Declaration of a firmware build.
// pub const Firmware = struct {
// const OutputFileMap = std.ArrayHashMap(BinaryFormat, std.Build.LazyPath, BinaryFormat.Context, false);
// const Modules = struct {
// app: *std.Build.Module,
// cpu: *std.Build.Module,
// chip: *std.Build.Module,
// board: ?*std.Build.Module,
// hal: ?*std.Build.Module,
// microzig: *std.Build.Module,
// };
// // privates:
// mz: *MicroZig,
// host_build: *std.Build,
// target: Target,
// output_files: OutputFileMap,
// // publics:
// /// The artifact that is built by Zig.
// artifact: *std.Build.Step.Compile,
// /// The options step that provides `microzig.config`. If you need custom configuration, you can add this here.
// config: *std.Build.Step.Options,
// /// Declaration of the MicroZig modules used by this firmware.
// modules: Modules,
// /// Path to the emitted elf file, if any.
// emitted_elf: ?std.Build.LazyPath = null,
// /// Returns the emitted ELF file for this firmware. This is useful if you need debug information
// /// or want to use a debugger like Segger, ST-Link or similar.
// ///
// /// **NOTE:** This is similar, but not equivalent to `std.Build.Step.Compile.getEmittedBin`. The call on the compile step does
// /// not include post processing of the ELF files necessary by certain targets.
// pub fn getEmittedElf(firmware: *Firmware) std.Build.LazyPath {
// if (firmware.emitted_elf == null) {
// const raw_elf = firmware.artifact.getEmittedBin();
// firmware.emitted_elf = if (firmware.target.binary_post_process) |binary_post_process|
// binary_post_process(firmware.host_build, raw_elf)
// else
// raw_elf;
// }
// return firmware.emitted_elf.?;
// }
// /// Returns the emitted binary for this firmware. The file is either in the preferred file format for
// /// the target or in `format` if not null.
// ///
// /// **NOTE:** The file returned here is the same file that will be installed.
// pub fn getEmittedBin(firmware: *Firmware, format: ?BinaryFormat) std.Build.LazyPath {
// const actual_format = firmware.resolveFormat(format);
// const gop = firmware.output_files.getOrPut(actual_format) catch @panic("out of memory");
// if (!gop.found_existing) {
// const elf_file = firmware.getEmittedElf();
// const basename = firmware.host_build.fmt("{s}{s}", .{
// firmware.artifact.name,
// actual_format.getExtension(),
// });
// gop.value_ptr.* = switch (actual_format) {
// .elf => elf_file,
// .bin => blk: {
// const objcopy = firmware.host_build.addObjCopy(elf_file, .{
// .basename = basename,
// .format = .bin,
// });
// break :blk objcopy.getOutput();
// },
// .hex => blk: {
// const objcopy = firmware.host_build.addObjCopy(elf_file, .{
// .basename = basename,
// .format = .hex,
// });
// break :blk objcopy.getOutput();
// },
// .uf2 => |family_id| blk: {
// const uf2_exe = firmware.mz.dependency("uf2", .{ .optimize = .ReleaseSafe }).artifact("elf2uf2");
// const convert = firmware.host_build.addRunArtifact(uf2_exe);
// convert.addArg("--family-id");
// convert.addArg(firmware.host_build.fmt("0x{X:0>4}", .{@intFromEnum(family_id)}));
// convert.addArg("--elf-path");
// convert.addFileArg(elf_file);
// convert.addArg("--output-path");
// break :blk convert.addOutputFileArg(basename);
// },
// .dfu => buildConfigError(firmware.host_build, "DFU is not implemented yet. See https://github.com/ZigEmbeddedGroup/microzig/issues/145 for more details!", .{}),
// .esp => buildConfigError(firmware.host_build, "ESP firmware image is not implemented yet. See https://github.com/ZigEmbeddedGroup/microzig/issues/146 for more details!", .{}),
// .custom => |generator| generator.convert(generator, elf_file),
// };
// }
// return gop.value_ptr.*;
// }
// pub const AppDependencyOptions = struct {
// depend_on_microzig: bool = false,
// };
// /// Adds a regular dependency to your application.
// pub fn addAppDependency(fw: *Firmware, name: []const u8, module: *std.Build.Module, options: AppDependencyOptions) void {
// if (options.depend_on_microzig) {
// module.dependencies.put("microzig", fw.modules.microzig) catch @panic("OOM");
// }
// fw.modules.app.dependencies.put(name, module) catch @panic("OOM");
// }
// pub fn addIncludePath(fw: *Firmware, path: std.Build.LazyPath) void {
// fw.artifact.addIncludePath(path);
// }
// pub fn addSystemIncludePath(fw: *Firmware, path: std.Build.LazyPath) void {
// fw.artifact.addSystemIncludePath(path);
// }
// pub fn addCSourceFile(fw: *Firmware, source: std.Build.Step.Compile.CSourceFile) void {
// fw.artifact.addCSourceFile(source);
// }
// pub fn addOptions(fw: *Firmware, module_name: []const u8, options: *std.Build.OptionsStep) void {
// fw.artifact.addOptions(module_name, options);
// fw.modules.app.dependencies.put(
// module_name,
// fw.host_build.createModule(.{
// .source_file = options.getOutput(),
// }),
// ) catch @panic("OOM");
// }
// pub fn addObjectFile(fw: *Firmware, source: std.Build.LazyPath) void {
// fw.artifact.addObjectFile(source);
// }
// fn resolveFormat(firmware: *Firmware, format: ?BinaryFormat) BinaryFormat {
// if (format) |fmt| return fmt;
// if (firmware.target.preferred_format) |fmt| return fmt;
// buildConfigError(firmware.host_build, "{s} has no preferred output format, please provide one in the `format` option.", .{
// firmware.target.chip.name,
// });
// }
// };
pub const cpus = struct {
pub const avr5 = microbuild.Cpu{
.name = "AVR5",
@ -843,139 +142,3 @@ pub const cpus = struct {
},
};
};
// fn buildConfigError(b: *std.Build, comptime fmt: []const u8, args: anytype) noreturn {
// const msg = b.fmt(fmt, args);
// @panic(msg);
// }
// fn dependency(mz: *MicroZig, name: []const u8, args: anytype) *std.Build.Dependency {
// return mz.self.builder.dependency(name, args);
// }
// 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);
// }

@ -5,11 +5,6 @@ pub fn build(b: *std.Build) void {
const microzig = MicroZig.createBuildEnvironment(b, .{
.self = "microzig", // package name of the build package (optional)
.core = "microzig-core", // package name of the core package (optional)
.board_support = &.{
// package names for BSP packages:
"microzig-bsp-nxp",
"microzig-bsp-rp2040",
},
});
const optimize = b.standardOptimizeOption(.{});

@ -4,19 +4,19 @@
.dependencies = .{
.microzig = .{
.url = "https://public.devspace.random-projects.net/microzig-build.tar.gz",
.hash = "122068db50e2a071cac3fc5b42d5cd2213ccb563986af60b941cb7af29b83df65b02",
.hash = "1220c87cc608598bdb4ae5ed6436c6fa3e126c57d3d1bbfaf01625c3af0c15da44e4",
},
.@"microzig-core" = .{
.url = "https://public.devspace.random-projects.net/microzig-core.tar.gz",
.hash = "12202df033d2b967108b25b8e66d8c8abcf690348a24baa35474a28086170ff31e54",
.hash = "1220a37d914f0585bbaeba2bc4d4d15586bef310a6af340af87f0e13fde0b4ddfb1a",
},
.@"microzig-bsp-nxp" = .{
.url = "https://public.devspace.random-projects.net/board-support/nxp/lpc.tar.gz",
.hash = "12201efd8d8b992caef770c87d78e6bd00bd73051bd1559bc342703f2e83650ef2f9",
.hash = "122040dc9467f6dac90a1376fff25350b2a5abd291904db7bea48a78db4f6e6dff13",
},
.@"microzig-bsp-rp2040" = .{
.url = "https://public.devspace.random-projects.net/board-support/raspberrypi/rp2040.tar.gz",
.hash = "1220154cd3634d0f3286cd2fb727cce9af3f3ab166772065e3efe4f9577128f4c559",
.hash = "1220142a13e590252deb7667569bdd3f6147c5b461f6b0343a825079a7dd3a24dea9",
},
},
}

@ -70,33 +70,26 @@ fn renderMicroZigTarget(stream: anytype, key: []const u8, target: microzig.Targe
try std.json.stringify(jtarget, .{}, stream);
}
fn renderTargetArray(stream: anytype, comptime array: type) !void {
inline for (comptime std.meta.declarations(array), 0..) |fld, i| {
fn renderTargetArray(stream: anytype, targets: []const microzig.BoardSupportPackageDefinition.TargetDefinition) !void {
for (targets, 0..) |target_def, i| {
if (i > 0) try stream.writeAll(",");
const target = comptime @field(array, fld.name);
if (@TypeOf(target) == type) {
// recurse
try renderTargetArray(stream, target);
} else {
try renderMicroZigTarget(
stream,
fld.name,
target,
target_def.id,
target_def.target,
);
}
}
}
pub fn main() !void {
const info = bsp.microzig_board_support;
var stdout = std.io.getStdOut().writer();
try stdout.writeAll("{ \"board-support\": {");
try stdout.writeAll("\"chips\":[");
try renderTargetArray(stdout, bsp.chips);
try stdout.writeAll("],\"boards\":[");
try renderTargetArray(stdout, bsp.boards);
try stdout.writeAll("\"targets\":[");
try renderTargetArray(stdout, info.targets);
try stdout.writeAll("]}}");
}

Loading…
Cancel
Save