diff --git a/.github/workflows/ports.yml b/.github/workflows/ports.yml index 26246a1ee..60f552390 100644 --- a/.github/workflows/ports.yml +++ b/.github/workflows/ports.yml @@ -96,12 +96,10 @@ jobs: working-directory: examples/gigadevice/gd32 - name: microchip/atmega - if: 0 # https://codeberg.org/ziglang/zig/issues/32108 run: zig build -Doptimize=ReleaseSmall working-directory: examples/microchip/atmega - name: microchip/attiny - if: 0 # https://codeberg.org/ziglang/zig/issues/32108 run: zig build -Doptimize=ReleaseSmall working-directory: examples/microchip/attiny diff --git a/core/src/cpus/avr_common.zig b/core/src/cpus/avr_common.zig index b85122329..a9173e6c8 100644 --- a/core/src/cpus/avr_common.zig +++ b/core/src/cpus/avr_common.zig @@ -17,9 +17,16 @@ pub const interrupt = struct { }; /// AVR interrupt handler function type. -pub const HandlerFn = extern union { +pub const HandlerFn = union(enum) { + /// Standard AVR interrupt handler. Disables global interrupts while it is + /// executing. Compiler generates prologue for pushing clobbered registers to + /// the stack, and corresponding epilogue with `reti` intsruction for + /// returning from an interrupt. signal: *const fn () callconv(.avr_signal) void, + /// Similar to the signal calling convention, but global interrupts are + /// enabled in the prologue, allowing for nested interrupts. interrupt: *const fn () callconv(.avr_interrupt) void, + /// No prologue, no epilogue, best for handwritten assembly. naked: *const fn () callconv(.naked) noreturn, }; @@ -78,8 +85,8 @@ pub fn generate_vector_table_asm(comptime jump_insn: JumpInstruction) []const u8 for (field_names[1..]) |field_name| { const handler = @field(interrupt_options, field_name); if (handler) |func| { - const isr = make_isr_handler(field_name, func); - asm_str = asm_str ++ jump_insn.to_string() ++ isr.exported_name ++ "\n"; + const isr_symbol = export_isr_handler(field_name, func); + asm_str = asm_str ++ jump_insn.to_string() ++ " " ++ isr_symbol ++ "\n"; } else { asm_str = asm_str ++ jump_insn.to_string() ++ " microzig_unhandled_vector\n"; } @@ -88,28 +95,14 @@ pub fn generate_vector_table_asm(comptime jump_insn: JumpInstruction) []const u8 return asm_str; } -fn make_isr_handler(comptime name: []const u8, comptime func: anytype) type { - const calling_convention = switch (@typeInfo(@TypeOf(func))) { - .@"fn" => |info| info.calling_convention, - .pointer => |info| switch (@typeInfo(info.child)) { - .@"fn" => |fn_info| fn_info.calling_convention, - else => @compileError("Declarations in 'interrupts' namespace must all be functions. '" ++ name ++ "' is not a function"), - }, - else => @compileError("Declarations in 'interrupts' namespace must all be functions. '" ++ name ++ "' is not a function"), - }; - - switch (calling_convention) { - .auto, .avr_signal, .avr_interrupt => {}, - else => @compileError("Calling conventions for interrupts must be 'avr_interrupt', 'avr_signal', or unspecified. The avr_signal calling convention leaves global interrupts disabled during the ISR, where avr_interrupt enables global interrupts for nested ISRs."), - } +fn export_isr_handler(comptime name: []const u8, comptime handler: HandlerFn) []const u8 { + const exported_name = "microzig_isr_" ++ name; - return struct { - pub const exported_name = "microzig_isr_" ++ name; + switch (handler) { + inline else => |func| @export(func, .{ .name = exported_name }), + } - comptime { - @export(func, .{ .name = exported_name }); - } - }; + return exported_name; } pub const startup_logic = struct { diff --git a/examples/microchip/attiny/build.zig b/examples/microchip/attiny/build.zig index df2730852..9bb152f85 100644 --- a/examples/microchip/attiny/build.zig +++ b/examples/microchip/attiny/build.zig @@ -16,7 +16,6 @@ pub fn build(b: *std.Build) void { .{ .target = mb.ports.attiny.boards.digispark, .name = "digispark_blinky", .file = "src/blinky.zig" }, .{ .target = mb.ports.attiny.boards.adafruit.trinket, .name = "trinket_blinky", .file = "src/blinky.zig" }, .{ .target = mb.ports.attiny.boards.adafruit.gemma, .name = "gemma_blinky", .file = "src/blinky.zig" }, - .{ .target = mb.ports.attiny.chips.attiny85, .name = "attiny85_blinky", .file = "src/blinky.zig" }, .{ .target = mb.ports.attiny.chips.attiny85, .name = "attiny85_blinky_interrupt", .file = "src/blinky_interrupt.zig" }, .{ .target = mb.ports.attiny.chips.attiny84, .name = "attiny84_blinky", .file = "src/blinky84.zig" }, .{ .target = mb.ports.attiny.chips.attiny1634, .name = "attiny1634_pwm_adc", .file = "src/attiny1634_pwm_adc.zig" }, diff --git a/examples/microchip/attiny/src/attiny1616_tca_rtc.zig b/examples/microchip/attiny/src/attiny1616_tca_rtc.zig index 8d7807d82..aa4e7fab0 100644 --- a/examples/microchip/attiny/src/attiny1616_tca_rtc.zig +++ b/examples/microchip/attiny/src/attiny1616_tca_rtc.zig @@ -7,6 +7,10 @@ const aux_led = hal.gpio.pin(.b, 5); const switch_pin = hal.gpio.pin(.a, 5); const Ramp = hal.progmem.Table(u8, 4, .{ 1, 4, 16, 64 }); +comptime { + _ = microzig.export_startup(); +} + pub fn main() void { hal.clock.use_default20_m_hz_div2(); diff --git a/examples/microchip/attiny/src/attiny1634_pwm_adc.zig b/examples/microchip/attiny/src/attiny1634_pwm_adc.zig index 6c0c9e3b4..77fe76a22 100644 --- a/examples/microchip/attiny/src/attiny1634_pwm_adc.zig +++ b/examples/microchip/attiny/src/attiny1634_pwm_adc.zig @@ -7,6 +7,10 @@ const fet_pwm = hal.gpio.pin(.c, 0); const voltage = hal.gpio.pin(.b, 1); const Gamma = hal.progmem.Table(u8, 4, .{ 0, 8, 32, 255 }); +comptime { + _ = microzig.export_startup(); +} + pub fn main() void { ch1_pwm.set_direction(.output); ch2_pwm.set_direction(.output); diff --git a/examples/microchip/attiny/src/blinky.zig b/examples/microchip/attiny/src/blinky.zig index 8e49f0467..78e7c3c41 100644 --- a/examples/microchip/attiny/src/blinky.zig +++ b/examples/microchip/attiny/src/blinky.zig @@ -3,6 +3,10 @@ const microzig = @import("microzig"); const led_pin = microzig.board.led_pin; +comptime { + _ = microzig.export_startup(); +} + pub fn main() void { led_pin.set_direction(.output); diff --git a/examples/microchip/attiny/src/blinky84.zig b/examples/microchip/attiny/src/blinky84.zig index 443fba4f0..d4900d8b0 100644 --- a/examples/microchip/attiny/src/blinky84.zig +++ b/examples/microchip/attiny/src/blinky84.zig @@ -2,6 +2,10 @@ const std = @import("std"); const microzig = @import("microzig"); const gpio = microzig.hal.gpio; +comptime { + _ = microzig.export_startup(); +} + // ATtiny84: use PA0 as the LED pin const led_pin = gpio.pin(.a, 0); @@ -22,7 +26,7 @@ pub fn busy_sleep(comptime limit: comptime_int) void { bits += 1; } - const I = std.meta.Int(.unsigned, bits); + const I = @Int(.unsigned, bits); var i: I = 0; while (i < limit) : (i += 1) { diff --git a/examples/microchip/attiny/src/blinky_interrupt.zig b/examples/microchip/attiny/src/blinky_interrupt.zig index 7034fff78..e34b09973 100644 --- a/examples/microchip/attiny/src/blinky_interrupt.zig +++ b/examples/microchip/attiny/src/blinky_interrupt.zig @@ -2,11 +2,15 @@ const std = @import("std"); const microzig = @import("microzig"); const gpio = microzig.hal.gpio; +comptime { + _ = microzig.export_startup(); +} + const led_pin = gpio.pin(.b, 1); pub const microzig_options: microzig.Options = .{ .interrupts = .{ - .INT0 = &my_int0_handler, + .INT0 = .{ .signal = &my_int0_handler }, }, }; diff --git a/port/microchip/attiny/src/boards/adafruit_gemma.zig b/port/microchip/attiny/src/boards/adafruit_gemma.zig index 24da7ac8c..74307ab8d 100644 --- a/port/microchip/attiny/src/boards/adafruit_gemma.zig +++ b/port/microchip/attiny/src/boards/adafruit_gemma.zig @@ -1,13 +1,8 @@ -pub const chip = @import("chip"); +const microzig = @import("microzig"); +const gpio = microzig.hal.gpio; pub const clock_frequencies = .{ .cpu = 8_000_000, }; -pub const pin_map = .{ - .D0 = "PB0", - .D1 = "PB1", - .D2 = "PB2", - // Built-in LED on D1 (PB1) - .LED = "PB1", -}; +pub const led_pin = gpio.pin(.b, 1); diff --git a/port/microchip/attiny/src/boards/digispark.zig b/port/microchip/attiny/src/boards/digispark.zig index 8245210fc..54cc4a7bb 100644 --- a/port/microchip/attiny/src/boards/digispark.zig +++ b/port/microchip/attiny/src/boards/digispark.zig @@ -1,17 +1,8 @@ -pub const chip = @import("chip"); +const microzig = @import("microzig"); +const gpio = microzig.hal.gpio; pub const clock_frequencies = .{ .cpu = 16_500_000, }; -pub const pin_map = .{ - // Digispark pin numbering maps to PORTB - .P0 = "PB0", - .P1 = "PB1", - .P2 = "PB2", - .P3 = "PB3", - .P4 = "PB4", - .P5 = "PB5", - // Built-in LED on P1 (PB1) - .LED = "PB1", -}; +pub const led_pin = gpio.pin(.b, 1);