Microzig Generation 2 Build Interface (#144)

* Starts to rework build framework.
* Fully reworks build API, builds with RP2040 again.
* Adds docs and doc generation.
* Renames source to register_definitions, makes Target.configure optional.
* Adds issue tracking links.
* Drops CI for now

---------

Co-authored-by: Felix "xq" Queißner <git@random-projects.net>
wch-ch32v003
Felix Queißner 1 year ago committed by GitHub
parent f0a6aa9ce1
commit 3bdb7381be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,7 +0,0 @@
steps:
- group: Build and Test
steps:
- label: Debug
command: zig build test
- label: ReleaseSmall
command: zig build test -Doptimize=ReleaseSmall

@ -1,24 +0,0 @@
name: Build
on:
push:
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [
ubuntu-latest,
windows-latest,
macos-latest,
]
steps:
- uses: actions/checkout@v2
- name: Setup Zig
uses: goto-bus-stop/setup-zig@v1.3.0
with:
version: 0.11.0
- name: Build tests
run: zig build test -Doptimize=ReleaseSmall

File diff suppressed because it is too large Load Diff

@ -0,0 +1,14 @@
.{
.name = "microzig",
.version = "0.1.0",
.dependencies = .{
.uf2 = .{
.url = "https://github.com/ZigEmbeddedGroup/uf2/archive/c523a4d23469282f95658a879f5ba925757dc9d9.tar.gz",
.hash = "12208530bdc194e8c1f3405ad681a409c7fabfe82735cd3972ec07c221a7786db03a",
},
.regz = .{
.url = "https://github.com/ZigEmbeddedGroup/regz/archive/b0ded63fc284da0ed9f4776eb7d1c4ad7175622d.tar.gz",
.hash = "1220e9299f949d3566a1dc4dd62caf82a06bb6c8ad5a693e62117b0941da9dc55ea2",
},
},
}

@ -1,6 +0,0 @@
const std = @import("std");
const Chip = @import("Chip.zig");
name: []const u8,
source: std.build.LazyPath,
chip: Chip,

@ -1,44 +0,0 @@
const std = @import("std");
const LazyPath = std.build.LazyPath;
const MemoryRegion = @import("MemoryRegion.zig");
const Cpu = @import("Cpu.zig");
const Chip = @This();
name: []const u8,
source: LazyPath,
cpu: Cpu,
hal: ?LazyPath = null,
json_register_schema: ?LazyPath = null,
memory_regions: []const MemoryRegion,
pub fn from_standard_paths(comptime root_dir: []const u8, args: struct {
name: []const u8,
cpu: Cpu,
memory_regions: []const MemoryRegion,
}) Chip {
return Chip{
.name = args.name,
.cpu = args.cpu,
.memory_regions = args.memory_regions,
.source = .{
.path = std.fmt.comptimePrint("{s}/chips/{s}.zig", .{
root_dir,
args.name,
}),
},
.hal = .{
.path = std.fmt.comptimePrint("{s}/hals/{s}.zig", .{
root_dir,
args.name,
}),
},
.json_register_schema = .{
.path = std.fmt.comptimePrint("{s}/chips/{s}.json", .{
root_dir,
args.name,
}),
},
};
}

@ -1,5 +0,0 @@
const std = @import("std");
name: []const u8,
source: std.build.LazyPath,
target: std.zig.CrossTarget,

@ -1,172 +0,0 @@
const std = @import("std");
const MemoryRegion = @import("MemoryRegion.zig");
const Chip = @import("Chip.zig");
const Step = std.build.Step;
const Build = std.Build;
const GeneratedFile = std.build.GeneratedFile;
const LinkerscriptStep = @This();
step: Step,
generated_file: std.build.GeneratedFile,
chip: Chip,
pub fn create(owner: *Build, chip: Chip) !*LinkerscriptStep {
var linkerscript = try owner.allocator.create(LinkerscriptStep);
linkerscript.* = LinkerscriptStep{
.step = Step.init(.{
.id = .custom,
.name = "linkerscript",
.owner = owner,
.makeFn = make,
}),
.generated_file = .{
.step = &linkerscript.step,
},
.chip = chip,
};
return linkerscript;
}
fn make(step: *Step, _: *std.Progress.Node) anyerror!void {
const linkerscript = @fieldParentPtr(LinkerscriptStep, "step", step);
const owner = linkerscript.step.owner;
const target = linkerscript.chip.cpu.target;
var contents = std.ArrayList(u8).init(owner.allocator);
const writer = contents.writer();
try writer.print(
\\/*
\\ * This file was auto-generated by microzig
\\ *
\\ * Target CPU: {s}
\\ * Target 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);
\\
\\
, .{ linkerscript.chip.cpu.name, linkerscript.chip.name });
try writer.writeAll("MEMORY\n{\n");
{
var counters = [2]usize{ 0, 0 };
for (linkerscript.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;
},
.custom => |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 (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 filename = try std.fmt.allocPrint(owner.allocator, "{s}_{s}.ld", .{
linkerscript.chip.name,
linkerscript.chip.cpu.name,
});
var hash = owner.cache.hash;
hash.addBytes(linkerscript.chip.name);
hash.addBytes(linkerscript.chip.cpu.name);
// TODO: hash more information to reduce chance of collision
for (linkerscript.chip.memory_regions) |memory_region| {
hash.add(memory_region.offset);
hash.add(memory_region.length);
}
const digest = hash.final();
const dir_path = try owner.cache_root.join(owner.allocator, &.{
"microzig",
&digest,
});
var dir = try owner.cache_root.handle.makeOpenPath(dir_path, .{});
defer dir.close();
const file = try dir.createFile(filename, .{});
defer file.close();
try file.writeAll(contents.items);
const full_path = owner.pathJoin(&.{ dir_path, filename });
linkerscript.generated_file.path = full_path;
}

@ -1,18 +0,0 @@
//! This module is meant to be used to define linking apis
kind: Kind,
offset: u64,
length: u64,
pub const Kind = union(enum) {
flash,
ram,
custom: RegionSpec,
};
pub const RegionSpec = struct {
name: []const u8,
executable: bool,
readable: bool,
writeable: bool,
};

@ -1,84 +0,0 @@
const std = @import("std");
const Cpu = @import("Cpu.zig");
fn root_dir() []const u8 {
return std.fs.path.dirname(@src().file) orelse ".";
}
pub const avr5 = Cpu{
.name = "AVR5",
.source = .{
.path = std.fmt.comptimePrint("{s}/cpus/avr5.zig", .{root_dir()}),
},
.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 = .{
.path = std.fmt.comptimePrint("{s}/cpus/cortex-m.zig", .{root_dir()}),
},
.target = std.zig.CrossTarget{
.cpu_arch = .thumb,
.cpu_model = .{ .explicit = &std.Target.arm.cpu.cortex_m0 },
.os_tag = .freestanding,
.abi = .none,
},
};
pub const cortex_m0plus = Cpu{
.name = "ARM Cortex-M0+",
.source = .{
.path = std.fmt.comptimePrint("{s}/cpus/cortex-m.zig", .{root_dir()}),
},
.target = std.zig.CrossTarget{
.cpu_arch = .thumb,
.cpu_model = .{ .explicit = &std.Target.arm.cpu.cortex_m0plus },
.os_tag = .freestanding,
.abi = .none,
},
};
pub const cortex_m3 = Cpu{
.name = "ARM Cortex-M3",
.source = .{
.path = std.fmt.comptimePrint("{s}/cpus/cortex-m.zig", .{root_dir()}),
},
.target = std.zig.CrossTarget{
.cpu_arch = .thumb,
.cpu_model = .{ .explicit = &std.Target.arm.cpu.cortex_m3 },
.os_tag = .freestanding,
.abi = .none,
},
};
pub const cortex_m4 = Cpu{
.name = "ARM Cortex-M4",
.source = .{
.path = std.fmt.comptimePrint("{s}/cpus/cortex-m.zig", .{root_dir()}),
},
.target = std.zig.CrossTarget{
.cpu_arch = .thumb,
.cpu_model = .{ .explicit = &std.Target.arm.cpu.cortex_m4 },
.os_tag = .freestanding,
.abi = .none,
},
};
pub const riscv32_imac = Cpu{
.name = "RISC-V 32-bit",
.source = .{
.path = std.fmt.comptimePrint("{s}/cpus/riscv32.zig", .{root_dir()}),
},
.target = std.zig.CrossTarget{
.cpu_arch = .riscv32,
.cpu_model = .{ .explicit = &std.Target.riscv.cpu.sifive_e21 },
.os_tag = .freestanding,
.abi = .none,
},
};
Loading…
Cancel
Save