Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ jobs:
nxp/lpc,
nxp/mcx,
stmicro/stm32,
texasinstruments/msp430,
raspberrypi/rp2xxx,
wch/ch32v,
no_hal/stm32_l031,
Expand Down
12 changes: 11 additions & 1 deletion build-internals/build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ pub const Target = struct {

/// 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,
bundle_compiler_rt: ?bool = true,

bundle_ubsan_rt: ?bool = null,

/// Determines whether the artifact produced for this target will exist solely in RAM. This will
/// inform whether we need to do any special handling e.g. of vector tables and whether we need
Expand Down Expand Up @@ -78,6 +80,7 @@ pub const Target = struct {
cpu: ?Cpu = null,
chip: ?Chip = null,
single_threaded: ?bool = null,
bundle_ubsan_rt: ?bool = null,
bundle_compiler_rt: ?bool = null,
ram_image: ?bool = null,
hal: ?HardwareAbstractionLayer = null,
Expand Down Expand Up @@ -105,6 +108,7 @@ pub const Target = struct {
.chip = chip,
.single_threaded = options.single_threaded orelse from.single_threaded,
.bundle_compiler_rt = options.bundle_compiler_rt orelse from.bundle_compiler_rt,
.bundle_ubsan_rt = options.bundle_ubsan_rt orelse from.bundle_ubsan_rt,
.ram_image = options.ram_image orelse from.ram_image,
.hal = options.hal orelse from.hal,
.board = options.board orelse from.board,
Expand Down Expand Up @@ -150,6 +154,12 @@ pub const Chip = struct {

/// Path to embassy stm32-data directory
embassy: LazyPath,

/// Single device from TI targetdb
targetdb: struct {
path: LazyPath,
device: []const u8,
},
},

/// The memory regions that are present in this chip.
Expand Down
34 changes: 34 additions & 0 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const port_list: []const struct {
.{ .name = "rp2xxx", .dep_name = "port/raspberrypi/rp2xxx" },
.{ .name = "stm32", .dep_name = "port/stmicro/stm32" },
.{ .name = "ch32v", .dep_name = "port/wch/ch32v" },
.{ .name = "msp430", .dep_name = "port/texasinstruments/msp430" },
};

const exe_targets: []const std.Target.Query = &.{
Expand Down Expand Up @@ -85,6 +86,7 @@ pub const PortSelect = struct {
rp2xxx: bool = false,
stm32: bool = false,
ch32v: bool = false,
msp430: bool = false,

pub const all: PortSelect = blk: {
var ret: PortSelect = undefined;
Expand Down Expand Up @@ -270,6 +272,8 @@ pub fn MicroBuild(port_select: PortSelect) type {
/// If set, overrides the `bundle_compiler_rt` property of the target.
bundle_compiler_rt: ?bool = null,

bundle_ubsan_rt: ?bool = null,

/// If set, overrides the `zig_target` property of the target.
zig_target: ?std.Target.Query = null,

Expand Down Expand Up @@ -427,7 +431,26 @@ pub fn MicroBuild(port_select: PortSelect) type {
regz_run.addDirectoryArg(path);
break :blk chips_dir.path(b, b.fmt("{s}.zig", .{target.chip.name}));
},
.targetdb => |targetdb| blk: {
const regz_run = b.addRunArtifact(regz_exe);

regz_run.addArg("--format");
regz_run.addArg(@tagName(target.chip.register_definition));

regz_run.addArg("--output_path"); // Write to a file
const chips_dir = regz_run.addOutputDirectoryArg("chips");

for (target.chip.patch_files) |patch_file| {
regz_run.addArg("--patch_path");
regz_run.addFileArg(patch_file);
}

regz_run.addArg("--device");
regz_run.addArg(targetdb.device);

regz_run.addDirectoryArg(targetdb.path);
break :blk chips_dir.path(b, b.fmt("{s}.zig", .{target.chip.name}));
},
.zig => |src| src,
};
const chip_mod = b.createModule(.{
Expand Down Expand Up @@ -487,6 +510,7 @@ pub fn MicroBuild(port_select: PortSelect) type {
};

fw.artifact.bundle_compiler_rt = options.bundle_compiler_rt orelse target.bundle_compiler_rt;
fw.artifact.bundle_ubsan_rt = options.bundle_ubsan_rt orelse target.bundle_ubsan_rt;

fw.artifact.link_gc_sections = options.strip_unused_symbols;
fw.artifact.link_function_sections = options.strip_unused_symbols;
Expand Down Expand Up @@ -756,6 +780,16 @@ pub fn MicroBuild(port_select: PortSelect) type {
},
}) catch @panic("OOM"),
};
} else if (target.cpu.model == &std.Target.msp430.cpu.msp430) {
return .{
.name = "MSP430",
.root_source_file = mb.core_dep.namedLazyPath("cpu_msp430"),
};
} else if (target.cpu.model == &std.Target.msp430.cpu.msp430x) {
return .{
.name = "MSP430X",
.root_source_file = mb.core_dep.namedLazyPath("cpu_msp430x"),
};
}

std.debug.panic(
Expand Down
3 changes: 2 additions & 1 deletion build.zig.zon
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,14 @@
// ports
.@"port/espressif/esp" = .{ .path = "port/espressif/esp", .lazy = true },
.@"port/gigadevice/gd32" = .{ .path = "port/gigadevice/gd32", .lazy = true },
.@"port/microchip/samd51" = .{ .path = "port/microchip/samd51", .lazy = true },
.@"port/microchip/atmega" = .{ .path = "port/microchip/atmega", .lazy = true },
.@"port/microchip/samd51" = .{ .path = "port/microchip/samd51", .lazy = true },
.@"port/nordic/nrf5x" = .{ .path = "port/nordic/nrf5x", .lazy = true },
.@"port/nxp/lpc" = .{ .path = "port/nxp/lpc", .lazy = true },
.@"port/nxp/mcx" = .{ .path = "port/nxp/mcx", .lazy = true },
.@"port/raspberrypi/rp2xxx" = .{ .path = "port/raspberrypi/rp2xxx", .lazy = true },
.@"port/stmicro/stm32" = .{ .path = "port/stmicro/stm32", .lazy = true },
.@"port/texasinstruments/msp430" = .{ .path = "port/texasinstruments/msp430", .lazy = true },
.@"port/wch/ch32v" = .{ .path = "port/wch/ch32v", .lazy = true },

// used for creating package tarballs
Expand Down
2 changes: 2 additions & 0 deletions core/build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ pub fn build(b: *std.Build) !void {
b.addNamedLazyPath("cpu_cortex_m", b.path("src/cpus/cortex_m.zig"));
b.addNamedLazyPath("cpu_riscv32", b.path("src/cpus/riscv32.zig"));
b.addNamedLazyPath("cpu_avr5", b.path("src/cpus/avr5.zig"));
b.addNamedLazyPath("cpu_msp430", b.path("src/cpus/msp430.zig"));
b.addNamedLazyPath("cpu_msp430x", b.path("src/cpus/msp430x.zig"));

const unit_tests = b.addTest(.{
// We're not using the `start.zig` entrypoint as it overrides too much
Expand Down
186 changes: 186 additions & 0 deletions core/src/cpus/msp430.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
const std = @import("std");
const microzig = @import("microzig");
const config = microzig.config;

const Interrupt = if (std.mem.eql(u8, config.chip_name, "MSP430G2553")) enum(u4) {
TRAPINT = 0,
PORT1 = 2,
PORT2 = 3,
ADC10 = 5,
USCIAB0TX = 6,
USCIAB0RX = 7,
TIMER0_A1 = 8,
TIMER0_A0 = 9,
WDT = 10,
COMPARATORA = 11,
TIMER1_A1 = 12,
TIMER1_A0 = 13,
NMI = 14,
} else if (std.mem.eql(u8, config.chip_name, "MSP430F5529")) enum(u6) {
RTC = 41,
PORT2 = 42,
TIMER2_A1 = 43,
TIMER2_A0 = 44,
USCI_B1 = 45,
USCI_A1 = 46,
PORT1 = 47,
TIMER1_A1 = 48,
TIMER1_A0 = 49,
DMA = 50,
USB_UBM = 51,
TIMER0_A1 = 52,
TIMER0_A0 = 53,
ADC12 = 54,
USCI_B0 = 55,
USCI_A0 = 56,
WDT = 57,
TIMER0_B1 = 58,
TIMER0_B0 = 59,
COMP_B = 60,
UNMI = 61,
SYSNMI = 62,
};

pub const InterruptOptions = microzig.utilities.GenerateInterruptOptions(&.{
.{ .InterruptEnum = Interrupt, .HandlerFn = interrupt.Handler },
});

// A placeholder for now
const VectorTable = if (std.mem.eql(u8, config.cpu_name, "MSP430X"))
extern struct {
table: [63]interrupt.Handler = [_]interrupt.Handler{.{ .c = interrupt.unhandled }} ** 63,
RESET: interrupt.Handler,
}
else if (std.mem.eql(u8, config.cpu_name, "MSP430"))
extern struct {
table: [15]interrupt.Handler = [_]interrupt.Handler{.{ .c = interrupt.unhandled }} ** 15,
RESET: interrupt.Handler,
}
else
@compileError("Invalid CPU, there are only MSP430 and MSP430X: " ++ config.cpu_name);

const vector_table: VectorTable = vector_table: {
var tmp: VectorTable = .{
.RESET = .{ .c = startup_logic._start },
};

// Apply interrupts
for (@typeInfo(@TypeOf(microzig.options.interrupts)).@"struct".fields) |field| {
const maybe_handler = @field(microzig.options.interrupts, field.name);
tmp.table[@intFromEnum(@field(Interrupt, field.name))] =
maybe_handler orelse .{ .c = interrupt.unhandled };
}

break :vector_table tmp;
};

pub const interrupt = struct {
// NOTE: We do not have an msp430 interrupt calling convention yet. This
// means that you need to exit the ISR with RETI
pub const Handler = extern union {
naked: *const fn () callconv(.naked) void,
c: *const fn () callconv(.c) void,
};

pub fn unhandled() callconv(.c) void {
while (true) {}
}

pub inline fn disable_interrupts() void {
// including a nop because it's suggested in literature
asm volatile (
\\DINT
\\NOP
::: .{});
}

pub inline fn enable_interrupts() void {
// including a nop because it's suggested in literature
asm volatile (
\\NOP
\\EINT
::: .{});
}
};

pub const startup_logic = struct {
extern fn microzig_main() noreturn;

pub fn _start() callconv(.c) noreturn {
const stack_init = comptime microzig.utilities.get_end_of_stack();
asm volatile (
\\MOV %[stack_init], SP
:
: [stack_init] "i" (@as(u32, @intFromPtr(stack_init))),
);

microzig.utilities.initialize_system_memories(.auto);
@call(.never_inline, microzig_main, .{});
}
};

pub fn export_startup_logic() void {
@export(&vector_table, .{
.name = "_vector_table",
.section = ".isr_vector",
.linkage = .strong,
});
@export(&startup_logic._start, .{
.name = "_start",
});
}

export fn memset(dest: [*]u8, ch: u8, count: usize) callconv(.c) [*]u8 {
// dest: R12
_ = ch; // R13
_ = count; // R14
asm volatile (
\\ MOV R12, R5
\\ ADD R5, R14
\\memset_loop:
\\ CMP R5, R12
\\ JEQ memset_done
\\ MOV.B R13, @R12
\\ INC R12
\\ JMP memset_loop
\\memset_done:
\\ SUB R12, R14
::: .{
.r5 = true,
// r12 doesn't go in the clobbers because it is restored before exiting
.r13 = true,
.r14 = true,
});

return dest;
}

export fn memcpy(dest: [*]u8, src: [*]const u8, count: usize) callconv(.c) [*]u8 {
// dest: R12
_ = src; // R13
_ = count; // R14
asm volatile (
\\ MOV R5, R12
\\ ADD R5, R14
\\memcpy_loop:
\\ CMP R5, R12
\\ JEQ memcpy_done
\\ MOV.B @R13, @R12
\\ INC R12
\\ INC R13
\\memcpy_done:
\\ SUB R12, R14
::: .{
.r5 = true,
// r12 doesn't go in the clobbers because it is restored before exiting
.r13 = true,
.r14 = true,
});

return dest;
}

export fn abort() callconv(.c) void {
@breakpoint();
while (true) {}
}
3 changes: 3 additions & 0 deletions core/src/cpus/msp430x.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const msp430 = @import("msp430.zig");
pub const interrupt = msp430.interrupt;
pub const export_startup_logic = msp430.export_startup_logic;
Empty file.
37 changes: 37 additions & 0 deletions examples/texasinstruments/msp430/build.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
const std = @import("std");
const microzig = @import("microzig");

const MicroBuild = microzig.MicroBuild(.{
.msp430 = true,
});

pub fn build(b: *std.Build) void {
const optimize = b.standardOptimizeOption(.{});

const mz_dep = b.dependency("microzig", .{});
const mb = MicroBuild.init(b, mz_dep) orelse return;

const targets = &.{
mb.ports.msp430.boards.launch_pad_msp430f5529,
mb.ports.msp430.boards.launch_pad_msp430g2553,
};

inline for (targets) |target| {
const empty = mb.add_firmware(.{
.name = b.fmt("empty_{s}", .{target.chip.name}),
.target = target,
.optimize = optimize,
.root_source_file = b.path("src/empty.zig"),
});

const blinky = mb.add_firmware(.{
.name = b.fmt("blinky_{s}", .{target.chip.name}),
.target = target,
.optimize = optimize,
.root_source_file = b.path("src/blinky.zig"),
});

mb.install_firmware(empty, .{});
mb.install_firmware(blinky, .{});
}
}
15 changes: 15 additions & 0 deletions examples/texasinstruments/msp430/build.zig.zon
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
.{
.name = .msp430,
.version = "0.0.1",
.minimum_zig_version = "0.15.2",
.fingerprint = 0x21359f74332f7448,
.dependencies = .{
.microzig = .{ .path = "../../.." },
},
.paths = .{
"README.md",
"build.zig",
"build.zig.zon",
"src",
},
}
Loading
Loading