diff --git a/src/core/start.zig b/src/core/start.zig index b84c395..27242c6 100644 --- a/src/core/start.zig +++ b/src/core/start.zig @@ -4,6 +4,57 @@ const microzig = @import("microzig"); pub usingnamespace app; +fn isValidField(field_name: []const u8) bool { + return !std.mem.startsWith(u8, field_name, "reserved") and + !std.mem.eql(u8, field_name, "initial_stack_pointer") and + !std.mem.eql(u8, field_name, "reset"); +} + +const VectorTable = microzig.chip.VectorTable; +export const vector_table: VectorTable linksection("microzig_flash_start") = blk: { + var tmp: microzig.chip.VectorTable = .{}; + if (@hasDecl(app, "interrupts")) { + if (@typeInfo(app.interrupts) != .Struct) + @compileLog("root.interrupts must be a struct"); + + inline for (@typeInfo(app.interrupts).Struct.decls) |decl| { + const calling_convention = @typeInfo(@TypeOf(@field(app.interrupts, decl.name))).Fn.calling_convention; + const handler = @field(app.interrupts, decl.name); + + if (!@hasField(VectorTable, decl.name)) { + var msg: []const u8 = "There is no such interrupt as '" ++ decl.name ++ "'. Declarations in 'interrupts' must be one of:\n"; + inline for (std.meta.fields(VectorTable)) |field| { + if (isValidField(field.name)) { + msg = msg ++ " " ++ field.name ++ "\n"; + } + } + + @compileError(msg); + } + + if (!isValidField(decl.name)) + @compileError("You are not allowed to specify '" ++ decl.name ++ "' in the vector table, for your sins you must now pay a $5 fine to the ZSF: https://github.com/sponsors/ziglang"); + + @field(tmp, decl.name) = switch (calling_convention) { + .C => .{ .C = handler }, + .Naked => .{ .Naked = handler }, + // for unspecified calling convention we are going to generate small wrapper + .Unspecified => .{ + .C = 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("unsupported calling convention for function " ++ decl.name), + }; + } + } + break :blk tmp; +}; + /// This is the logical entry point for microzig. /// It will invoke the main function from the root source file /// and provides error return handling as well as a event loop if requested. diff --git a/src/modules/chips/lpc1768/lpc1768.zig b/src/modules/chips/lpc1768/lpc1768.zig index 9341851..edf8614 100644 --- a/src/modules/chips/lpc1768/lpc1768.zig +++ b/src/modules/chips/lpc1768/lpc1768.zig @@ -3,7 +3,7 @@ const micro = @import("microzig"); pub const cpu = @import("cpu"); pub const registers = @import("registers.zig"); - +pub const VectorTable = registers.VectorTable; pub const PinTarget = enum(u2) { func00 = 0b00, func01 = 0b01, diff --git a/src/modules/chips/lpc1768/registers.zig b/src/modules/chips/lpc1768/registers.zig index 436e99e..e0d36c5 100644 --- a/src/modules/chips/lpc1768/registers.zig +++ b/src/modules/chips/lpc1768/registers.zig @@ -21798,55 +21798,3 @@ pub const VectorTable = extern struct { USBActivity: InterruptVector = makeUnhandledHandler("USBActivity"), CANActivity: InterruptVector = makeUnhandledHandler("CANActivity"), }; - -fn isValidField(field_name: []const u8) bool { - return !std.mem.startsWith(u8, field_name, "reserved") and - !std.mem.eql(u8, field_name, "initial_stack_pointer") and - !std.mem.eql(u8, field_name, "reset"); -} - -export const vectors: VectorTable linksection("microzig_flash_start") = blk: { - var temp: VectorTable = .{}; - if (@hasDecl(root, "vector_table")) { - const vector_table = root.vector_table; - if (@typeInfo(vector_table) != .Struct) - @compileLog("root.vector_table must be a struct"); - - inline for (@typeInfo(vector_table).Struct.decls) |decl| { - const calling_convention = @typeInfo(@TypeOf(@field(vector_table, decl.name))).Fn.calling_convention; - const handler = @field(vector_table, decl.name); - - if (!@hasField(VectorTable, decl.name)) { - var msg: []const u8 = "There is no such interrupt as '" ++ decl.name ++ "', declarations in 'root.vector_table' must be one of:\n"; - inline for (std.meta.fields(VectorTable)) |field| { - if (isValidField(field.name)) { - msg = msg ++ " " ++ field.name ++ "\n"; - } - } - - @compileError(msg); - } - - if (!isValidField(decl.name)) - @compileError("You are not allowed to specify '" ++ decl.name ++ "' in the vector table, for your sins you must now pay a $5 fine to the ZSF: https://github.com/sponsors/ziglang"); - - @field(temp, decl.name) = switch (calling_convention) { - .C => .{ .C = handler }, - .Naked => .{ .Naked = handler }, - // for unspecified calling convention we are going to generate small wrapper - .Unspecified => .{ - .C = 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("unsupported calling convention for function " ++ decl.name), - }; - } - } - break :blk temp; -}; - diff --git a/src/modules/chips/nrf52/nrf52.zig b/src/modules/chips/nrf52/nrf52.zig index 5ae1cd3..f9865cd 100644 --- a/src/modules/chips/nrf52/nrf52.zig +++ b/src/modules/chips/nrf52/nrf52.zig @@ -1,2 +1,3 @@ pub const cpu = @import("cpu"); pub const registers = @import("registers.zig"); +pub const VectorTable = registers.VectorTable; diff --git a/src/modules/chips/stm32f103/stm32f103.zig b/src/modules/chips/stm32f103/stm32f103.zig index 6ede441..f9865cd 100644 --- a/src/modules/chips/stm32f103/stm32f103.zig +++ b/src/modules/chips/stm32f103/stm32f103.zig @@ -1,4 +1,3 @@ -const std = @import("std"); - pub const cpu = @import("cpu"); pub const registers = @import("registers.zig"); +pub const VectorTable = registers.VectorTable; diff --git a/src/modules/chips/stm32f303/stm32f303.zig b/src/modules/chips/stm32f303/stm32f303.zig index 9c13c60..4fb8ca0 100644 --- a/src/modules/chips/stm32f303/stm32f303.zig +++ b/src/modules/chips/stm32f303/stm32f303.zig @@ -3,6 +3,7 @@ const micro = @import("microzig"); pub const cpu = @import("cpu"); pub const registers = @import("registers.zig"); +pub const VectorTable = registers.VectorTable; pub fn parsePin(comptime spec: []const u8) type { const invalid_format_msg = "The given pin '" ++ spec ++ "' has an invalid format. Pins must follow the format \"P{Port}{Pin}\" scheme."; diff --git a/tests/interrupt.zig b/tests/interrupt.zig index 73dd4ea..f16fdd8 100644 --- a/tests/interrupt.zig +++ b/tests/interrupt.zig @@ -5,7 +5,8 @@ const micro = @import("microzig"); // right now. pub const panic = micro.panic; -pub const vector_table = struct { + +pub const interrupts = struct { pub fn SysTick() void { @panic("hit systick!"); }