Avr interrupt overloading (#29)

* mostly implemented, need different patch in order to wire it in

* add generated code

* turned interrupts back on

* fix symbol names for avr

* export in cpu file

* Emits a function instead of a `void` symbol.

* add interrupt test to avr

* Removes invalid comment.

Co-authored-by: Felix "xq" Queißner <git@masterq32.de>
wch-ch32v003
Matt Knight 3 years ago committed by GitHub
parent 823ff6577f
commit b2793e2589
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -31,7 +31,7 @@ pub fn build(b: *std.build.Builder) !void {
Test{ .name = "uart-sync", .source = "tests/uart-sync.zig", .uses_uart = true, .on_avr = false },
// Note: this example uses the systick interrupt and therefore only for arm microcontrollers
Test{ .name = "interrupt", .source = "tests/interrupt.zig", .on_avr = false },
Test{ .name = "interrupt", .source = "tests/interrupt.zig", .on_avr = true },
};
const filter = b.option(std.Target.Cpu.Arch, "filter-target", "Filters for a certain cpu target");

@ -1,5 +1,6 @@
const std = @import("std");
const micro = @import("microzig");
pub usingnamespace @import("registers.zig");
pub const cpu = micro.cpu;
const Port = enum(u8) {

File diff suppressed because it is too large Load Diff

@ -1,4 +1,5 @@
const std = @import("std");
const microzig = @import("microzig");
pub inline fn sei() void {
asm volatile ("sei");
@ -24,46 +25,77 @@ pub inline fn cbi(comptime reg: u5, comptime bit: u3) void {
);
}
pub const startup_logic = struct {
comptime {
asm (
\\.section microzig_flash_start
\\ jmp _start
\\ jmp _unhandled_vector
\\ jmp _unhandled_vector
\\ jmp _unhandled_vector
\\ jmp _unhandled_vector
\\ jmp _unhandled_vector
\\ jmp _unhandled_vector
\\ jmp _unhandled_vector
\\ jmp _unhandled_vector
\\ jmp _unhandled_vector
\\ jmp _unhandled_vector
\\ jmp _unhandled_vector
\\ jmp _unhandled_vector
\\ jmp _unhandled_vector
\\ jmp _unhandled_vector
\\ jmp _unhandled_vector
\\ jmp _unhandled_vector
\\ jmp _unhandled_vector
\\ jmp _unhandled_vector
\\ jmp _unhandled_vector
\\ jmp _unhandled_vector
\\ jmp _unhandled_vector
\\ jmp _unhandled_vector
\\ jmp _unhandled_vector
\\ jmp _unhandled_vector
\\ jmp _unhandled_vector
);
pub const vector_table = blk: {
std.debug.assert(std.mem.eql(u8, "RESET", std.meta.fields(microzig.chip.VectorTable)[0].name));
var asm_str: []const u8 = "jmp microzig_start\n";
const has_interrupts = @hasDecl(microzig.app, "interrupts");
if (has_interrupts) {
if (@hasDecl(microzig.app.interrupts, "RESET"))
@compileError("Not allowed to overload the reset vector");
inline for (std.meta.declarations(microzig.app.interrupts)) |decl| {
if (!@hasField(microzig.chip.VectorTable, decl.name)) {
var msg: []const u8 = "There is no such interrupt as '" ++ decl.name ++ "'. ISRs the 'interrupts' namespace must be one of:\n";
inline for (std.meta.fields(microzig.chip.VectorTable)) |field| {
if (!std.mem.eql(u8, "RESET", field.name)) {
msg = msg ++ " " ++ field.name ++ "\n";
}
}
export fn _unhandled_vector() callconv(.Naked) noreturn {
@compileError(msg);
}
}
}
inline for (std.meta.fields(microzig.chip.VectorTable)[1..]) |field| {
const new_insn = if (has_interrupts) overload: {
if (@hasDecl(microzig.app.interrupts, field.name)) {
const handler = @field(microzig.app.interrupts, field.name);
const calling_convention = switch (@typeInfo(@TypeOf(@field(microzig.app.interrupts, field.name)))) {
.Fn => |info| info.calling_convention,
else => @compileError("Declarations in 'interrupts' namespace must all be functions. '" ++ field.name ++ "' is not a function"),
};
const exported_fn = switch (calling_convention) {
.Unspecified => struct {
fn wrapper() callconv(.C) void {
if (calling_convention == .Unspecified) // TODO: workaround for some weird stage1 bug
@call(.{ .modifier = .always_inline }, handler, .{});
}
}.wrapper,
else => @compileError("Just leave interrupt handlers with an unspecified calling convention"),
};
const exported_name = "microzig_isr_" ++ field.name;
const options = .{ .name = exported_name, .linkage = .Strong };
@export(exported_fn, options);
break :overload "jmp " ++ exported_name;
} else {
break :overload "jmp microzig_unhandled_vector";
}
} else "jmp microzig_unhandled_vector";
asm_str = asm_str ++ new_insn ++ "\n";
}
const T = struct {
fn _start() callconv(.Naked) void {
asm volatile (asm_str);
}
};
break :blk T._start;
};
pub const startup_logic = struct {
export fn microzig_unhandled_vector() callconv(.Naked) noreturn {
@panic("Unhandled interrupt");
}
extern fn microzig_main() noreturn;
export fn _start() callconv(.Naked) noreturn {
export fn microzig_start() callconv(.Naked) noreturn {
// At startup the stack pointer is at the end of RAM
// so, no need to set it manually!

@ -1,4 +1,5 @@
const micro = @import("microzig");
const builtin = @import("builtin");
// this program will only work on arm microcontrollers, and it might not
// actually run correctly at first, it's just a test for declaring interrupts
@ -6,14 +7,19 @@ const micro = @import("microzig");
pub const panic = micro.panic;
pub const interrupts = struct {
pub const interrupts = switch (builtin.cpu.arch) {
.avr => struct {
pub fn INT0() void {
@panic("hit PCINT0");
}
},
else => struct {
pub fn SysTick() void {
@panic("hit systick!");
}
},
};
pub fn main() void {
while (true) {
micro.cpu.wfi();
}
while (true) {}
}

Loading…
Cancel
Save