Skip to content

Commit

Permalink
Improved the interrupts interface (#2)
Browse files Browse the repository at this point in the history
This project now handles interrupts differently.

Previously, the project created the default interrupt handlers through a
series of PROVIDE directives in the linker script. The handlers were
then overriden by users using an @export() call. However this approach
seemed quite janky, as it relied on the linker script and did stuff out
of zig code that directly affected the compilation process.

Now, the project takes a different approach: the default interrupt
vector is defined as a weak symbol in an object file that's compiled
separately from the rest of the project. This object file is then linked
to the main project again. The user can still override the default
handlers with the interrupts module. This is a more elegant approach,
reliant exclusively on Zig code, without relying on janky and obscure
linker script directives.
  • Loading branch information
lucas-yotsui committed Aug 19, 2024
1 parent 2feaa78 commit 9a8a5eb
Show file tree
Hide file tree
Showing 5 changed files with 938 additions and 537 deletions.
84 changes: 15 additions & 69 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,21 @@ pub fn init(b: *std.Build, options: UniMicroOptions) *std.Build.Step.InstallFile
// and then calls the user's main function.
elf.entry = .{ .symbol_name = "unimicro_main" };

const default_interrupts_vector = b.addObject(.{
.name = "default_interrupts_vector",
.root_source_file = .{
.cwd_relative = b.fmt("{s}/hal/{s}/{s}/default_interrupts.zig", .{
root(),
options.target_platform.manufacturer,
options.target_platform.name,
}),
},
.target = target,
.optimize = options.optimization_level,
.single_threaded = options.target_platform.single_threaded,
});
elf.addObject(default_interrupts_vector);

// Module with the HAL to be imported by the user.
const hal_module = b.createModule(.{
.root_source_file = .{
Expand Down Expand Up @@ -131,74 +146,6 @@ pub const supported_chips = .{
MemorySection{ .origin = 0x0800_0000, .length = 256 * Units.KB, .type = .FLASH },
MemorySection{ .origin = 0x2000_0000, .length = 128 * Units.KB, .type = .RAM },
},
.interrupts = &.{
"nmi_fault",
"hard_fault",
"memory_management_fault",
"bus_fault",
"usage_fault",
"svcall",
"debug_monitor",
"pendsv",
"systick",
"window_watchdog",
"exti_16_pvd",
"exti_21_tamper_timestamp",
"exti_22_rtc_wakeup",
"flash",
"rcc",
"exti_line_0",
"exti_line_1",
"exti_line_2",
"exti_line_3",
"exti_line_4",
"dma1_stream0",
"dma1_stream1",
"dma1_stream2",
"dma1_stream3",
"dma1_stream4",
"dma1_stream5",
"dma1_stream6",
"adc",
"exti_line_5_to_9",
"timer1_break_and_timer9_global",
"timer1_update_and_timer10_global",
"timer1_trigger_and_commutation_and_timer11_global",
"timer1_capture_compare",
"timer2_global",
"timer3_global",
"timer4_global",
"i2c1_event",
"i2c1_error",
"i2c2_event",
"i2c2_error",
"spi1_global",
"spi2_global",
"usart1_global",
"usart2_global",
"exti_line_10_to_15",
"exti_line_17_and_rtc_alarm",
"exti_line_18_and_usb_otg_fs_wakeup",
"dma1_stream7",
"sdio_global",
"timer5_global",
"spi3_global",
"dma2_stream0",
"dma2_stream1",
"dma2_stream2",
"dma2_stream3",
"dma2_stream4",
"usb_otg_fs_global",
"dma2_stream5",
"dma2_stream6",
"dma2_stream7",
"usart6_global",
"i2c3_event",
"i2c3_error",
"fpu_global",
"spi4_global",
"spi5_global",
},
},
},
};
Expand Down Expand Up @@ -236,7 +183,6 @@ pub const Chip = struct {
cpu: Cpu,
memory_sections: []const MemorySection,

interrupts: []const []const u8,
single_threaded: bool = false,
};

Expand Down
93 changes: 93 additions & 0 deletions hal/stmicro/stm32f411cc/default_interrupts.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
comptime {
const NestedVectorInterruptController = extern struct {
stack_top: *const u32 = @extern(*const u32, .{ .name = "_stack_top" }),
reset: Handler = @extern(*const fn () callconv(.C) void, .{ .name = "unimicro_main" }),
nmi_fault: Handler = default_int_handler,
hard_fault: Handler = default_int_handler,
memory_management_fault: Handler = default_int_handler,
bus_fault: Handler = default_int_handler,
usage_fault: Handler = default_int_handler,
reserved_1: u32 = 0,
reserved_2: u32 = 0,
reserved_3: u32 = 0,
reserved_4: u32 = 0,
sv_call: Handler = default_int_handler,
debug_monitor: Handler = default_int_handler,
reserved_5: u32 = 0,
pend_sv: Handler = default_int_handler,
systick: Handler = default_int_handler,
window_watchdog: Handler = default_int_handler,
exti_16_pvd: Handler = default_int_handler,
exti_21_tamper_timestamp: Handler = default_int_handler,
exti_22_rtc_wakeup: Handler = default_int_handler,
flash: Handler = default_int_handler,
rcc: Handler = default_int_handler,
exti_line_0: Handler = default_int_handler,
exti_line_1: Handler = default_int_handler,
exti_line_2: Handler = default_int_handler,
exti_line_3: Handler = default_int_handler,
exti_line_4: Handler = default_int_handler,
dma1_stream0: Handler = default_int_handler,
dma1_stream1: Handler = default_int_handler,
dma1_stream2: Handler = default_int_handler,
dma1_stream3: Handler = default_int_handler,
dma1_stream4: Handler = default_int_handler,
dma1_stream5: Handler = default_int_handler,
dma1_stream6: Handler = default_int_handler,
adc: Handler = default_int_handler,
exti_line_5_to_9: Handler = default_int_handler,
timer1_break_and_timer9_global: Handler = default_int_handler,
timer1_update_and_timer10_global: Handler = default_int_handler,
timer1_trigger_and_commutation_and_timer11_global: Handler = default_int_handler,
timer1_capture_compare: Handler = default_int_handler,
timer2_global: Handler = default_int_handler,
timer3_global: Handler = default_int_handler,
timer4_global: Handler = default_int_handler,
i2c1_event: Handler = default_int_handler,
i2c1_error: Handler = default_int_handler,
i2c2_event: Handler = default_int_handler,
i2c2_error: Handler = default_int_handler,
spi1_global: Handler = default_int_handler,
spi2_global: Handler = default_int_handler,
usart1_global: Handler = default_int_handler,
usart2_global: Handler = default_int_handler,
exti_line_10_to_15: Handler = default_int_handler,
exti_line_17_and_rtc_alarm: Handler = default_int_handler,
exti_line_18_and_usb_otg_fs_wakeup: Handler = default_int_handler,
dma1_stream7: Handler = default_int_handler,
sdio_global: Handler = default_int_handler,
timer5_global: Handler = default_int_handler,
spi3_global: Handler = default_int_handler,
dma2_stream0: Handler = default_int_handler,
dma2_stream1: Handler = default_int_handler,
dma2_stream2: Handler = default_int_handler,
dma2_stream3: Handler = default_int_handler,
dma2_stream4: Handler = default_int_handler,
usb_otg_fs_global: Handler = default_int_handler,
dma2_stream5: Handler = default_int_handler,
dma2_stream6: Handler = default_int_handler,
dma2_stream7: Handler = default_int_handler,
usart6_global: Handler = default_int_handler,
i2c3_event: Handler = default_int_handler,
i2c3_error: Handler = default_int_handler,
fpu_global: Handler = default_int_handler,
spi4_global: Handler = default_int_handler,
spi5_global: Handler = default_int_handler,

const Handler = *const fn () callconv(.C) void;

// Default handler, does absolutely nothing but to wait for
// inspection with a debugger
fn default_int_handler() callconv(.C) void {
while (true) asm volatile ("");
}

comptime {
@export(default_int_handler, .{ .name = "default_int_handler", .linkage = .weak });
}
};

const default_nvic: NestedVectorInterruptController = .{};

@export(default_nvic, .{ .name = "vector_table", .section = ".vector", .linkage = .weak });
}
Loading

0 comments on commit 9a8a5eb

Please sign in to comment.