Create LinkerscriptStep (#7)

* create linkerscript step

* catch up to master, do some cleanup

* remove references to micro_linker

* commas

* remove package

* use root path trick for cpus and chips

* remove duped file
wch-ch32v003
Matt Knight 3 years ago committed by GitHub
parent af7aa777f9
commit 5a1e72f380
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -9,8 +9,14 @@ on:
jobs:
build:
runs-on: ubuntu-latest
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [
ubuntu-latest,
windows-latest,
macos-latest,
]
steps:
- name: Checkout
uses: actions/checkout@v2

3
.gitignore vendored

@ -1,2 +1,3 @@
zig-cache/
dev-scripts/
dev-scripts/
zig-out

@ -3,6 +3,13 @@
//! This means we need to use addExecutable() instead of using
const std = @import("std");
const boards = @import("src/modules/boards.zig");
const chips = @import("src/modules/chips.zig");
const LinkerscriptStep = @import("src/modules/LinkerScriptStep.zig");
const Board = boards.Board;
const Chip = chips.Chip;
const Cpu = chips.Cpu;
pub fn build(b: *std.build.Builder) !void {
const mode = b.standardReleaseOptions();
@ -12,9 +19,9 @@ pub fn build(b: *std.build.Builder) !void {
const BuildConfig = struct { name: []const u8, backing: Backing };
const all_backings = [_]BuildConfig{
//BuildConfig{ .name = "boards.arduino_nano", .backing = Backing{ .board = pkgs.boards.arduino_nano } },
BuildConfig{ .name = "boards.mbed_lpc1768", .backing = Backing{ .board = pkgs.boards.mbed_lpc1768 } },
BuildConfig{ .name = "boards.mbed_lpc1768", .backing = Backing{ .board = boards.mbed_lpc1768 } },
//BuildConfig{ .name = "chips.atmega328p", .backing = Backing{ .chip = pkgs.chips.atmega328p } },
//BuildConfig{ .name = "chips.lpc1768", .backing = Backing{ .chip = pkgs.chips.lpc1768 } },
BuildConfig{ .name = "chips.lpc1768", .backing = Backing{ .chip = chips.lpc1768 } },
};
const Test = struct { name: []const u8, source: []const u8 };
@ -45,7 +52,12 @@ pub fn build(b: *std.build.Builder) !void {
}
}
fn addEmbeddedExecutable(builder: *std.build.Builder, name: []const u8, source: []const u8, backing: Backing) !*std.build.LibExeObjStep {
fn addEmbeddedExecutable(
builder: *std.build.Builder,
name: []const u8,
source: []const u8,
backing: Backing,
) !*std.build.LibExeObjStep {
const Pkg = std.build.Pkg;
const microzig_base = Pkg{
@ -71,40 +83,9 @@ fn addEmbeddedExecutable(builder: *std.build.Builder, name: []const u8, source:
.path = .{ .path = chip.cpu.path },
.dependencies = &[_]Pkg{ microzig_base, pkgs.mmio },
},
Pkg{
.name = "microzig-linker",
.path = .{ .path = "src/modules/linker/linker.zig" },
},
},
};
const linker_script_name = blk: {
const hash = hash_blk: {
var hasher = std.hash.SipHash128(1, 2).init("abcdefhijklmnopq");
hasher.update(chip.name);
hasher.update(chip.path);
hasher.update(chip.cpu.name);
hasher.update(chip.cpu.path);
var mac: [16]u8 = undefined;
hasher.final(&mac);
break :hash_blk mac;
};
const file_prefix = "zig-cache/microzig/";
const file_suffix = ".ld";
var ld_file_name: [file_prefix.len + 2 * hash.len + file_suffix.len]u8 = undefined;
const filename = try std.fmt.bufPrint(&ld_file_name, "{s}{}{s}", .{
file_prefix,
std.fmt.fmtSliceHexLower(&hash),
file_suffix,
});
break :blk builder.dupe(filename);
};
const config_file_name = blk: {
const hash = hash_blk: {
var hasher = std.hash.SipHash128(1, 2).init("abcdefhijklmnopq");
@ -156,22 +137,7 @@ fn addEmbeddedExecutable(builder: *std.build.Builder, name: []const u8, source:
.path = .{ .path = config_file_name },
};
const build_options = builder.addOptions();
build_options.addOption([]const u8, "microzig_chip_name", chip.name);
build_options.addOption([]const u8, "microzig_cpu_name", chip.cpu.name);
build_options.addOption([]const u8, "microzig_target_triple", try chip.cpu.target.zigTriple(builder.allocator));
const linkerscript_gen = builder.addExecutable("linkerscript-gen", "src/tools/linkerscript-gen.zig");
linkerscript_gen.addPackage(chip_package);
linkerscript_gen.addPackage(Pkg{
.name = "microzig-linker",
.path = .{ .path = "src/modules/linker/linker.zig" },
});
linkerscript_gen.addOptions("build_options", build_options);
const linkerscript_invocation = linkerscript_gen.run();
linkerscript_invocation.addArg(linker_script_name);
const linkerscript = try LinkerscriptStep.create(builder, chip);
const exe = builder.addExecutable(name, source);
// might not be true for all machines (Pi Pico), but
@ -179,8 +145,7 @@ fn addEmbeddedExecutable(builder: *std.build.Builder, name: []const u8, source:
exe.single_threaded = true;
exe.setTarget(chip.cpu.target);
exe.setLinkerScriptPath(.{ .path = linker_script_name });
exe.step.dependOn(&linkerscript_invocation.step);
exe.setLinkerScriptPath(.{ .generated = &linkerscript.generated_file });
// TODO:
// - Generate the linker scripts from the "chip" or "board" package instead of using hardcoded ones.
@ -216,25 +181,6 @@ fn addEmbeddedExecutable(builder: *std.build.Builder, name: []const u8, source:
return exe;
}
const Board = struct {
name: []const u8,
path: []const u8,
chip: Chip,
};
const Chip = struct {
name: []const u8,
path: []const u8,
cpu: Cpu,
};
const Cpu = struct {
name: []const u8,
path: []const u8,
target: std.zig.CrossTarget,
linker_script: []const u8,
};
pub const Backing = union(enum) {
board: Board,
chip: Chip,
@ -245,55 +191,4 @@ const pkgs = struct {
.name = "microzig-mmio",
.path = .{ .path = "src/core/mmio.zig" },
};
const cpus = struct {
const avr5 = Cpu{
.name = "AVR5",
.path = "src/modules/cpus/avr/avr5.zig",
.linker_script = "src/modules/cpus/avr/linker.ld",
.target = std.zig.CrossTarget{
.cpu_arch = .avr,
.cpu_model = .{ .explicit = &std.Target.avr.cpu.avr5 },
.os_tag = .freestanding,
.abi = .eabi,
},
};
const cortex_m3 = Cpu{
.name = "ARM Cortex-M3",
.path = "src/modules/cpus/cortex-m3/cortex-m3.zig",
.linker_script = "src/modules/cpus/cortex-m3/linker.ld",
.target = std.zig.CrossTarget{
.cpu_arch = .arm,
.cpu_model = .{ .explicit = &std.Target.arm.cpu.cortex_m3 },
.os_tag = .freestanding,
.abi = .none,
},
};
};
const chips = struct {
const atmega328p = Chip{
.name = "ATmega328p",
.path = "src/modules/chips/atmega328p/atmega328p.zig",
.cpu = cpus.avr5,
};
const lpc1768 = Chip{
.name = "NXP LPC1768",
.path = "src/modules/chips/lpc1768/lpc1768.zig",
.cpu = cpus.cortex_m3,
};
};
const boards = struct {
const arduino_nano = Board{
.name = "Arduino Nano",
.path = "src/modules/boards/arduino-nano/arduino-nano.zig",
.chip = chips.atmega328p,
};
const mbed_lpc1768 = Board{
.name = "mbed LPC1768",
.path = "src/modules/boards/mbed-lpc1768/mbed-lpc1768.zig",
.chip = chips.lpc1768,
};
};
};

@ -27,7 +27,9 @@ fn writerWrite(ctx: void, string: []const u8) DebugErr!usize {
const DebugWriter = std.io.Writer(void, DebugErr, writerWrite);
pub fn write(string: []const u8) void {
if (!micro.config.has_board and !@hasDecl(micro.board, "debugWrite"))
if (!micro.config.has_board)
return;
if (!@hasDecl(micro.board, "debugWrite"))
return;
micro.board.debugWrite(string);

@ -1,46 +1,72 @@
const std = @import("std");
const build_options = @import("build_options");
const chip = @import("chip");
const micro_linker = @import("microzig-linker");
const target = blk: {
@setEvalBranchQuota(20_000);
const t = std.zig.CrossTarget.parse(std.zig.CrossTarget.ParseOptions{
.arch_os_abi = build_options.microzig_target_triple,
}) catch unreachable;
std.debug.assert(t.cpu_arch != null);
break :blk t;
};
pub fn main() !u8 {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const allocator = &arena.allocator;
const args = try std.process.argsAlloc(allocator);
const MemoryRegion = @import("MemoryRegion.zig");
const Chip = @import("chips.zig").Chip;
const Step = std.build.Step;
const Builder = std.build.Builder;
const GeneratedFile = std.build.GeneratedFile;
const LinkerscriptStep = @This();
step: Step,
generated_file: std.build.GeneratedFile,
builder: *Builder,
chip: Chip,
pub fn create(builder: *Builder, chip: Chip) !*LinkerscriptStep {
var hasher = std.hash.SipHash128(1, 2).init("abcdefhijklmnopq");
hasher.update(chip.name);
hasher.update(chip.path);
hasher.update(chip.cpu.name);
hasher.update(chip.cpu.path);
var mac: [16]u8 = undefined;
hasher.final(&mac);
const filename = try std.fmt.allocPrint(builder.allocator, "{}{s}", .{
std.fmt.fmtSliceHexLower(&mac),
".ld",
});
const path = try std.fs.path.join(builder.allocator, &.{
"zig-cache",
"microzig",
filename,
});
try std.fs.cwd().makePath(std.fs.path.dirname(path).?);
var ret = try builder.allocator.create(LinkerscriptStep);
ret.* = LinkerscriptStep{
.step = Step.init(.custom, "linkerscript", builder.allocator, make),
.generated_file = .{
.step = &ret.step,
.path = path,
},
.builder = builder,
.chip = chip,
};
return ret;
}
if (args.len < 2) {
std.log.err("Missing CLI argument. Give the output file name!", .{});
return 1;
}
fn make(step: *Step) !void {
const linkerscript = @fieldParentPtr(LinkerscriptStep, "step", step);
const file = try std.fs.cwd().createFile(linkerscript.generated_file.path.?, .{});
defer file.close();
if (std.fs.path.dirname(args[1])) |dir| {
try std.fs.cwd().makePath(dir);
const target = linkerscript.chip.cpu.target;
if (target.cpu_arch == null) {
std.log.err("target does not have 'cpu_arch'", .{});
return error.NoCpuArch;
}
var dest_file = try std.fs.cwd().createFile(args[1], .{});
defer dest_file.close();
var writer = dest_file.writer();
try writer.writeAll("/*\n * This file was auto-generated by microzig\n *\n");
try writer.print(" * Target CPU: {s}\n", .{build_options.microzig_cpu_name});
try writer.print(" * Target Chip: {s}\n", .{build_options.microzig_chip_name});
try writer.writeAll(" */\n\n");
try writer.writeAll(
const writer = file.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
@ -48,12 +74,12 @@ pub fn main() !u8 {
\\ENTRY(microzig_main);
\\
\\
);
, .{ linkerscript.chip.cpu.name, linkerscript.chip.name });
try writer.writeAll("MEMORY\n{\n");
{
var counters = [2]usize{ 0, 0 };
for (chip.memory_regions) |region| {
for (linkerscript.chip.memory_regions) |region| {
// flash (rx!w) : ORIGIN = 0x00000000, LENGTH = 512k
switch (region.kind) {
@ -134,5 +160,4 @@ pub fn main() !u8 {
// \\ ASSERT( (SIZEOF(.text) + SIZEOF(.data) > LENGTH(flash0)), "Error: .text + .data is too large for flash!" );
// \\
// );
return 0;
}

@ -0,0 +1,18 @@
//! 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,
};

@ -0,0 +1,20 @@
const chips = @import("chips.zig");
const Chip = chips.Chip;
pub const Board = struct {
name: []const u8,
path: []const u8,
chip: Chip,
};
pub const arduino_nano = Board{
.name = "Arduino Nano",
.path = "src/modules/boards/arduino-nano/arduino-nano.zig",
.chip = chips.atmega328p,
};
pub const mbed_lpc1768 = Board{
.name = "mbed LPC1768",
.path = "src/modules/boards/mbed-lpc1768/mbed-lpc1768.zig",
.chip = chips.lpc1768,
};

@ -0,0 +1,37 @@
const std = @import("std");
const cpus = @import("cpus.zig");
const MemoryRegion = @import("MemoryRegion.zig");
fn root() []const u8 {
return std.fs.path.dirname(@src().file) orelse unreachable;
}
const root_path = root() ++ "/";
pub const Chip = struct {
name: []const u8,
path: []const u8,
cpu: cpus.Cpu,
memory_regions: []const MemoryRegion,
};
pub const atmega328p = Chip{
.name = "ATmega328p",
.path = root_path ++ "chips/atmega328p/atmega328p.zig",
.cpu = cpus.avr5,
.memory_regions = &[_]MemoryRegion{
MemoryRegion{ .offset = 0x000000, .length = 32 * 1024, .kind = .flash },
MemoryRegion{ .offset = 0x800100, .length = 2048, .kind = .ram },
},
};
pub const lpc1768 = Chip{
.name = "NXP LPC1768",
.path = root_path ++ "chips/lpc1768/lpc1768.zig",
.cpu = cpus.cortex_m3,
.memory_regions = &[_]MemoryRegion{
MemoryRegion{ .offset = 0x00000000, .length = 512 * 1024, .kind = .flash },
MemoryRegion{ .offset = 0x10000000, .length = 32 * 1024, .kind = .ram },
MemoryRegion{ .offset = 0x2007C000, .length = 32 * 1024, .kind = .ram },
},
};

@ -1,13 +1,6 @@
const std = @import("std");
const micro_linker = @import("microzig-linker");
pub const cpu = @import("cpu");
pub const memory_regions = [_]micro_linker.MemoryRegion{
micro_linker.MemoryRegion{ .offset = 0x000000, .length = 32 * 1024, .kind = .flash },
micro_linker.MemoryRegion{ .offset = 0x800100, .length = 2048, .kind = .ram },
};
const Port = enum(u8) {
B = 1,
C = 2,

@ -1,16 +1,9 @@
const std = @import("std");
const micro = @import("microzig");
const micro_linker = @import("microzig-linker");
pub const cpu = @import("cpu");
pub const registers = @import("registers.zig");
pub const memory_regions = [_]micro_linker.MemoryRegion{
micro_linker.MemoryRegion{ .offset = 0x00000000, .length = 512 * 1024, .kind = .flash },
micro_linker.MemoryRegion{ .offset = 0x10000000, .length = 32 * 1024, .kind = .ram },
micro_linker.MemoryRegion{ .offset = 0x2007C000, .length = 32 * 1024, .kind = .ram },
};
pub const PinTarget = enum(u2) {
func00 = 0b00,
func01 = 0b01,

@ -0,0 +1,35 @@
const std = @import("std");
fn root() []const u8 {
return std.fs.path.dirname(@src().file) orelse unreachable;
}
const root_path = root() ++ "/";
pub const Cpu = struct {
name: []const u8,
path: []const u8,
target: std.zig.CrossTarget,
};
pub const avr5 = Cpu{
.name = "AVR5",
.path = root_path ++ "cpus/avr/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_m3 = Cpu{
.name = "ARM Cortex-M3",
.path = root_path ++ "cpus/cortex-m3/cortex-m3.zig",
.target = std.zig.CrossTarget{
.cpu_arch = .arm,
.cpu_model = .{ .explicit = &std.Target.arm.cpu.cortex_m3 },
.os_tag = .freestanding,
.abi = .none,
},
};

@ -71,11 +71,11 @@ pub const startup_logic = struct {
extern fn microzig_main() noreturn;
extern var microzig_data_start: c_void;
extern var microzig_data_end: c_void;
extern var microzig_bss_start: c_void;
extern var microzig_bss_end: c_void;
extern const microzig_data_load_start: c_void;
extern var microzig_data_start: anyopaque;
extern var microzig_data_end: anyopaque;
extern var microzig_bss_start: anyopaque;
extern var microzig_bss_end: anyopaque;
extern const microzig_data_load_start: anyopaque;
fn _start() callconv(.C) noreturn {

@ -1,20 +0,0 @@
//! This module is meant to be used to define linking apis
pub const MemoryRegion = struct {
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,
};
};
Loading…
Cancel
Save