interrupt generation for chips (#16)

wch-ch32v003
Matt Knight 3 years ago committed by GitHub
parent 152db2ae5f
commit c34d8b73d5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -110,10 +110,11 @@ pub fn addEmbeddedExecutable(
.dependencies = &[_]Pkg{ .dependencies = &[_]Pkg{
microzig_pkg, microzig_pkg,
pkgs.mmio, pkgs.mmio,
config_pkg,
Pkg{ Pkg{
.name = "cpu", .name = "cpu",
.path = .{ .path = chip.cpu.path }, .path = .{ .path = chip.cpu.path },
.dependencies = &[_]Pkg{ microzig_pkg, pkgs.mmio, config_pkg }, .dependencies = &[_]Pkg{ microzig_pkg, pkgs.mmio },
}, },
}, },
}; };

@ -23,5 +23,5 @@ pub const mbed_lpc1768 = Board{
pub const stm32f3discovery = Board{ pub const stm32f3discovery = Board{
.name = "STM32F3DISCOVERY", .name = "STM32F3DISCOVERY",
.path = root_path ++ "boards/stm32f3discovery/stm32f3discovery.zig", .path = root_path ++ "boards/stm32f3discovery/stm32f3discovery.zig",
.chip = chips.stm32f30x, .chip = chips.stm32f303vc,
}; };

@ -40,9 +40,9 @@ pub const stm32f103x8 = Chip{
}, },
}; };
pub const stm32f30x = Chip{ pub const stm32f303vc = Chip{
.name = "STM32F30x", .name = "STM32F303VC",
.path = root_path ++ "chips/stm32f30x/stm32f30x.zig", .path = root_path ++ "chips/stm32f303/stm32f303.zig",
.cpu = cpus.cortex_m4, .cpu = cpus.cortex_m4,
.memory_regions = &.{ .memory_regions = &.{
MemoryRegion{ .offset = 0x08000000, .length = 256 * 1024, .kind = .flash }, MemoryRegion{ .offset = 0x08000000, .length = 256 * 1024, .kind = .flash },

@ -21724,3 +21724,129 @@ pub const GPIO = extern struct {
PINCLR31: u1, // bit offset: 31 desc: Fast GPIO output value Clear bits. Bit 0 in CLRx controls pin Px[0], bit 31 in CLRx controls pin Px[31]. 0 = Controlled pin output is unchanged. 1 = Controlled pin output is set to LOW. PINCLR31: u1, // bit offset: 31 desc: Fast GPIO output value Clear bits. Bit 0 in CLRx controls pin Px[0], bit 31 in CLRx controls pin Px[31]. 0 = Controlled pin output is unchanged. 1 = Controlled pin output is set to LOW.
}); });
}; };
const std = @import("std");
const root = @import("root");
const cpu = @import("cpu");
const config = @import("microzig-config");
const InterruptVector = extern union {
C: fn () callconv(.C) void,
Naked: fn () callconv(.Naked) void,
// Interrupt is not supported on arm
};
fn makeUnhandledHandler(comptime str: []const u8) InterruptVector {
return InterruptVector{
.C = struct {
fn unhandledInterrupt() callconv(.C) noreturn {
@panic("unhandled interrupt: " ++ str);
}
}.unhandledInterrupt,
};
}
pub const VectorTable = extern struct {
initial_stack_pointer: u32 = config.end_of_stack,
Reset: InterruptVector = InterruptVector{ .C = cpu.startup_logic._start },
NMI: InterruptVector = makeUnhandledHandler("NMI"),
HardFault: InterruptVector = makeUnhandledHandler("HardFault"),
MemManage: InterruptVector = makeUnhandledHandler("MemManage"),
BusFault: InterruptVector = makeUnhandledHandler("BusFault"),
UsageFault: InterruptVector = makeUnhandledHandler("UsageFault"),
reserved: [4]u32 = .{ 0, 0, 0, 0 },
SVCall: InterruptVector = makeUnhandledHandler("SVCall"),
DebugMonitor: InterruptVector = makeUnhandledHandler("DebugMonitor"),
reserved1: u32 = 0,
PendSV: InterruptVector = makeUnhandledHandler("PendSV"),
SysTick: InterruptVector = makeUnhandledHandler("SysTick"),
WDT: InterruptVector = makeUnhandledHandler("WDT"),
TIMER0: InterruptVector = makeUnhandledHandler("TIMER0"),
TIMER1: InterruptVector = makeUnhandledHandler("TIMER1"),
TIMER2: InterruptVector = makeUnhandledHandler("TIMER2"),
TIMER3: InterruptVector = makeUnhandledHandler("TIMER3"),
UART0: InterruptVector = makeUnhandledHandler("UART0"),
UART1: InterruptVector = makeUnhandledHandler("UART1"),
UART2: InterruptVector = makeUnhandledHandler("UART2"),
UART3: InterruptVector = makeUnhandledHandler("UART3"),
PWM1: InterruptVector = makeUnhandledHandler("PWM1"),
I2C0: InterruptVector = makeUnhandledHandler("I2C0"),
I2C1: InterruptVector = makeUnhandledHandler("I2C1"),
I2C2: InterruptVector = makeUnhandledHandler("I2C2"),
SPI: InterruptVector = makeUnhandledHandler("SPI"),
SSP0: InterruptVector = makeUnhandledHandler("SSP0"),
SSP1: InterruptVector = makeUnhandledHandler("SSP1"),
PLL0: InterruptVector = makeUnhandledHandler("PLL0"),
RTC: InterruptVector = makeUnhandledHandler("RTC"),
EINT0: InterruptVector = makeUnhandledHandler("EINT0"),
EINT1: InterruptVector = makeUnhandledHandler("EINT1"),
EINT2: InterruptVector = makeUnhandledHandler("EINT2"),
EINT3: InterruptVector = makeUnhandledHandler("EINT3"),
ADC: InterruptVector = makeUnhandledHandler("ADC"),
BOD: InterruptVector = makeUnhandledHandler("BOD"),
USB: InterruptVector = makeUnhandledHandler("USB"),
CAN: InterruptVector = makeUnhandledHandler("CAN"),
DMA: InterruptVector = makeUnhandledHandler("DMA"),
I2S: InterruptVector = makeUnhandledHandler("I2S"),
ENET: InterruptVector = makeUnhandledHandler("ENET"),
RIT: InterruptVector = makeUnhandledHandler("RIT"),
MCPWM: InterruptVector = makeUnhandledHandler("MCPWM"),
QEI: InterruptVector = makeUnhandledHandler("QEI"),
PLL1: InterruptVector = makeUnhandledHandler("PLL1"),
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;
};

@ -17770,3 +17770,273 @@ pub const USB = extern struct {
padding1: u1 = 0, padding1: u1 = 0,
}); });
}; };
const std = @import("std");
const root = @import("root");
const cpu = @import("cpu");
const config = @import("microzig-config");
const InterruptVector = extern union {
C: fn () callconv(.C) void,
Naked: fn () callconv(.Naked) void,
// Interrupt is not supported on arm
};
fn makeUnhandledHandler(comptime str: []const u8) InterruptVector {
return InterruptVector{
.C = struct {
fn unhandledInterrupt() callconv(.C) noreturn {
@panic("unhandled interrupt: " ++ str);
}
}.unhandledInterrupt,
};
}
pub const VectorTable = extern struct {
initial_stack_pointer: u32 = config.end_of_stack,
Reset: InterruptVector = InterruptVector{ .C = cpu.startup_logic._start },
NMI: InterruptVector = makeUnhandledHandler("NMI"),
HardFault: InterruptVector = makeUnhandledHandler("HardFault"),
MemManage: InterruptVector = makeUnhandledHandler("MemManage"),
BusFault: InterruptVector = makeUnhandledHandler("BusFault"),
UsageFault: InterruptVector = makeUnhandledHandler("UsageFault"),
reserved: [4]u32 = .{ 0, 0, 0, 0 },
SVCall: InterruptVector = makeUnhandledHandler("SVCall"),
DebugMonitor: InterruptVector = makeUnhandledHandler("DebugMonitor"),
reserved1: u32 = 0,
PendSV: InterruptVector = makeUnhandledHandler("PendSV"),
SysTick: InterruptVector = makeUnhandledHandler("SysTick"),
/// Window Watchdog interrupt
WWDG: InterruptVector = makeUnhandledHandler("WWDG"),
/// PVD through EXTI line detection interrupt
PVD: InterruptVector = makeUnhandledHandler("PVD"),
/// Tamper interrupt
TAMPER: InterruptVector = makeUnhandledHandler("TAMPER"),
/// RTC global interrupt
RTC: InterruptVector = makeUnhandledHandler("RTC"),
/// Flash global interrupt
FLASH: InterruptVector = makeUnhandledHandler("FLASH"),
/// RCC global interrupt
RCC: InterruptVector = makeUnhandledHandler("RCC"),
/// EXTI Line0 interrupt
EXTI0: InterruptVector = makeUnhandledHandler("EXTI0"),
/// EXTI Line1 interrupt
EXTI1: InterruptVector = makeUnhandledHandler("EXTI1"),
/// EXTI Line2 interrupt
EXTI2: InterruptVector = makeUnhandledHandler("EXTI2"),
/// EXTI Line3 interrupt
EXTI3: InterruptVector = makeUnhandledHandler("EXTI3"),
/// EXTI Line4 interrupt
EXTI4: InterruptVector = makeUnhandledHandler("EXTI4"),
/// DMA1 Channel1 global interrupt
DMA1_Channel1: InterruptVector = makeUnhandledHandler("DMA1_Channel1"),
/// DMA1 Channel2 global interrupt
DMA1_Channel2: InterruptVector = makeUnhandledHandler("DMA1_Channel2"),
/// DMA1 Channel3 global interrupt
DMA1_Channel3: InterruptVector = makeUnhandledHandler("DMA1_Channel3"),
/// DMA1 Channel4 global interrupt
DMA1_Channel4: InterruptVector = makeUnhandledHandler("DMA1_Channel4"),
/// DMA1 Channel5 global interrupt
DMA1_Channel5: InterruptVector = makeUnhandledHandler("DMA1_Channel5"),
/// DMA1 Channel6 global interrupt
DMA1_Channel6: InterruptVector = makeUnhandledHandler("DMA1_Channel6"),
/// DMA1 Channel7 global interrupt
DMA1_Channel7: InterruptVector = makeUnhandledHandler("DMA1_Channel7"),
/// ADC1 global interrupt; ADC2 global interrupt
ADC: InterruptVector = makeUnhandledHandler("ADC"),
/// CAN1 TX interrupts
CAN1_TX: InterruptVector = makeUnhandledHandler("CAN1_TX"),
/// CAN1 RX0 interrupts
CAN1_RX0: InterruptVector = makeUnhandledHandler("CAN1_RX0"),
/// CAN1 RX1 interrupt
CAN1_RX1: InterruptVector = makeUnhandledHandler("CAN1_RX1"),
/// CAN1 SCE interrupt
CAN1_SCE: InterruptVector = makeUnhandledHandler("CAN1_SCE"),
/// EXTI Line[9:5] interrupts
EXTI9_5: InterruptVector = makeUnhandledHandler("EXTI9_5"),
/// TIM1 Break interrupt and TIM9 global interrupt
TIM1_BRK_TIM9: InterruptVector = makeUnhandledHandler("TIM1_BRK_TIM9"),
/// TIM1 Update interrupt and TIM10 global interrupt
TIM1_UP_TIM10: InterruptVector = makeUnhandledHandler("TIM1_UP_TIM10"),
/// TIM1 Trigger and Commutation interrupts and TIM11 global interrupt
TIM1_TRG_COM_TIM11: InterruptVector = makeUnhandledHandler("TIM1_TRG_COM_TIM11"),
/// TIM1 Capture Compare interrupt
TIM1_CC: InterruptVector = makeUnhandledHandler("TIM1_CC"),
/// TIM2 global interrupt
TIM2: InterruptVector = makeUnhandledHandler("TIM2"),
/// TIM3 global interrupt
TIM3: InterruptVector = makeUnhandledHandler("TIM3"),
/// TIM4 global interrupt
TIM4: InterruptVector = makeUnhandledHandler("TIM4"),
/// I2C1 event interrupt
I2C1_EV: InterruptVector = makeUnhandledHandler("I2C1_EV"),
/// I2C1 error interrupt
I2C1_ER: InterruptVector = makeUnhandledHandler("I2C1_ER"),
/// I2C2 event interrupt
I2C2_EV: InterruptVector = makeUnhandledHandler("I2C2_EV"),
/// I2C2 error interrupt
I2C2_ER: InterruptVector = makeUnhandledHandler("I2C2_ER"),
/// SPI1 global interrupt
SPI1: InterruptVector = makeUnhandledHandler("SPI1"),
/// SPI2 global interrupt
SPI2: InterruptVector = makeUnhandledHandler("SPI2"),
/// USART1 global interrupt
USART1: InterruptVector = makeUnhandledHandler("USART1"),
/// USART2 global interrupt
USART2: InterruptVector = makeUnhandledHandler("USART2"),
/// USART3 global interrupt
USART3: InterruptVector = makeUnhandledHandler("USART3"),
/// EXTI Line[15:10] interrupts
EXTI15_10: InterruptVector = makeUnhandledHandler("EXTI15_10"),
/// RTC Alarms through EXTI line interrupt
RTCAlarm: InterruptVector = makeUnhandledHandler("RTCAlarm"),
/// USB Device FS Wakeup through EXTI line interrupt
USB_FS_WKUP: InterruptVector = makeUnhandledHandler("USB_FS_WKUP"),
/// TIM8 Break interrupt and TIM12 global interrupt
TIM8_BRK_TIM12: InterruptVector = makeUnhandledHandler("TIM8_BRK_TIM12"),
/// TIM8 Update interrupt and TIM13 global interrupt
TIM8_UP_TIM13: InterruptVector = makeUnhandledHandler("TIM8_UP_TIM13"),
/// TIM8 Trigger and Commutation interrupts and TIM14 global interrupt
TIM8_TRG_COM_TIM14: InterruptVector = makeUnhandledHandler("TIM8_TRG_COM_TIM14"),
/// TIM8 Capture Compare interrupt
TIM8_CC: InterruptVector = makeUnhandledHandler("TIM8_CC"),
/// ADC3 global interrupt
ADC3: InterruptVector = makeUnhandledHandler("ADC3"),
/// FSMC global interrupt
FSMC: InterruptVector = makeUnhandledHandler("FSMC"),
/// SDIO global interrupt
SDIO: InterruptVector = makeUnhandledHandler("SDIO"),
/// TIM5 global interrupt
TIM5: InterruptVector = makeUnhandledHandler("TIM5"),
/// SPI3 global interrupt
SPI3: InterruptVector = makeUnhandledHandler("SPI3"),
/// UART4 global interrupt
UART4: InterruptVector = makeUnhandledHandler("UART4"),
/// UART5 global interrupt
UART5: InterruptVector = makeUnhandledHandler("UART5"),
/// TIM6 global interrupt
TIM6: InterruptVector = makeUnhandledHandler("TIM6"),
/// TIM7 global interrupt
TIM7: InterruptVector = makeUnhandledHandler("TIM7"),
/// DMA2 Channel1 global interrupt
DMA2_Channel1: InterruptVector = makeUnhandledHandler("DMA2_Channel1"),
/// DMA2 Channel2 global interrupt
DMA2_Channel2: InterruptVector = makeUnhandledHandler("DMA2_Channel2"),
/// DMA2 Channel3 global interrupt
DMA2_Channel3: InterruptVector = makeUnhandledHandler("DMA2_Channel3"),
/// DMA2 Channel4 and DMA2 Channel5 global interrupt
DMA2_Channel4_5: InterruptVector = makeUnhandledHandler("DMA2_Channel4_5"),
};
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;
};

@ -1,6 +1,5 @@
const std = @import("std"); const std = @import("std");
const root = @import("root"); const root = @import("root");
const config = @import("microzig-config");
pub fn sei() void { pub fn sei() void {
asm volatile ("cpsie i"); asm volatile ("cpsie i");
@ -43,92 +42,6 @@ pub fn clrex() void {
} }
pub const startup_logic = struct { pub const startup_logic = struct {
const InterruptVector = extern union {
C: fn () callconv(.C) void,
Naked: fn () callconv(.Naked) void,
// Interrupt is not supported on arm
};
const VectorTable = extern struct {
initial_stack_pointer: u32 = config.end_of_stack,
reset: InterruptVector = InterruptVector{ .C = _start },
nmi: InterruptVector = makeUnhandledHandler("nmi"),
hard_fault: InterruptVector = makeUnhandledHandler("hard_fault"),
mpu_fault: InterruptVector = makeUnhandledHandler("mpu_fault"),
bus_fault: InterruptVector = makeUnhandledHandler("bus_fault"),
usage_fault: InterruptVector = makeUnhandledHandler("usage_fault"),
secure_fault: InterruptVector = makeUnhandledHandler("secure_fault"),
reserved: [3]u32 = .{ 0, 0, 0 },
svc: InterruptVector = makeUnhandledHandler("svc"),
debugmon: InterruptVector = makeUnhandledHandler("debugmon"),
reserved1: u32 = 0,
pendsv: InterruptVector = makeUnhandledHandler("pendsv"),
systick: InterruptVector = makeUnhandledHandler("systick"),
};
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;
};
fn makeUnhandledHandler(comptime str: []const u8) InterruptVector {
return InterruptVector{
.C = struct {
fn unhandledInterrupt() callconv(.C) noreturn {
@panic("unhandled interrupt: " ++ str);
}
}.unhandledInterrupt,
};
}
extern fn microzig_main() noreturn; extern fn microzig_main() noreturn;
extern var microzig_data_start: anyopaque; extern var microzig_data_start: anyopaque;
@ -137,7 +50,7 @@ pub const startup_logic = struct {
extern var microzig_bss_end: anyopaque; extern var microzig_bss_end: anyopaque;
extern const microzig_data_load_start: anyopaque; extern const microzig_data_load_start: anyopaque;
fn _start() callconv(.C) noreturn { pub fn _start() callconv(.C) noreturn {
// fill .bss with zeroes // fill .bss with zeroes
{ {

@ -117,14 +117,142 @@ class MMIOFileGenerator:
self.write_line("};") self.write_line("};")
# TODO: descriptions on system interrupts/exceptions, turn on system interrupts/exceptions
def generate_startup_and_interrupts(self, interrupts):
self.write_line("")
self.write_line(
"""
const std = @import(\"std\");
const root = @import(\"root\");
const cpu = @import(\"cpu\");
const config = @import(\"microzig-config\");
const InterruptVector = extern union {
C: fn () callconv(.C) void,
Naked: fn () callconv(.Naked) void,
// Interrupt is not supported on arm
};
fn makeUnhandledHandler(comptime str: []const u8) InterruptVector {
return InterruptVector{
.C = struct {
fn unhandledInterrupt() callconv(.C) noreturn {
@panic(\"unhandled interrupt: \" ++ str);
}
}.unhandledInterrupt,
};
}
pub const VectorTable = extern struct {
initial_stack_pointer: u32 = config.end_of_stack,
Reset: InterruptVector = InterruptVector{ .C = cpu.startup_logic._start },
NMI: InterruptVector = makeUnhandledHandler(\"NMI\"),
HardFault: InterruptVector = makeUnhandledHandler(\"HardFault\"),
MemManage: InterruptVector = makeUnhandledHandler(\"MemManage\"),
BusFault: InterruptVector = makeUnhandledHandler(\"BusFault\"),
UsageFault: InterruptVector = makeUnhandledHandler(\"UsageFault\"),
reserved: [4]u32 = .{ 0, 0, 0, 0 },
SVCall: InterruptVector = makeUnhandledHandler(\"SVCall\"),
DebugMonitor: InterruptVector = makeUnhandledHandler(\"DebugMonitor\"),
reserved1: u32 = 0,
PendSV: InterruptVector = makeUnhandledHandler(\"PendSV\"),
SysTick: InterruptVector = makeUnhandledHandler(\"SysTick\"),\n
""")
reserved_count = 2
expected_next_value = 0
for interrupt in interrupts:
if expected_next_value > interrupt.value:
raise Exception("out of order interrupt list")
while expected_next_value < interrupt.value:
self.write_line(f" reserved{reserved_count}: u32 = 0,")
expected_next_value += 1
reserved_count += 1
if interrupt.description is not None:
self.write_line(f"\n /// {interrupt.description}")
self.write_line(f" {interrupt.name}: InterruptVector = makeUnhandledHandler(\"{interrupt.name}\"),")
expected_next_value += 1
self.write_line("};")
self.write_line(
"""
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;
};
""")
def generate_file(self, device): def generate_file(self, device):
self.write_line("// generated using svd2zig.py\n// DO NOT EDIT") self.write_line("// generated using svd2zig.py\n// DO NOT EDIT")
self.write_line(f"// based on {device.name} version {device.version}") self.write_line(f"// based on {device.name} version {device.version}")
self.write_line("const mmio = @import(\"microzig-mmio\").mmio;") self.write_line("const mmio = @import(\"microzig-mmio\").mmio;")
self.write_line(f"const Name = \"{device.name}\";") self.write_line(f"const Name = \"{device.name}\";")
for peripherial in device.peripherals: interrupts = {}
self.generate_peripherial_declaration(peripherial) for peripheral in device.peripherals:
self.generate_peripherial_declaration(peripheral)
if peripheral.interrupts != None:
for interrupt in peripheral.interrupts:
if interrupt.value in interrupts and interrupts[interrupt.value].description != interrupt.description:
interrupts[interrupt.value].description += "; " + interrupt.description
else:
interrupts[interrupt.value] = interrupt
interrupts = list(map(lambda i: i[1], sorted(interrupts.items())))
for interrupt in interrupts:
if interrupt.description is not None:
interrupt.description = ' '.join(interrupt.description.split())
self.generate_startup_and_interrupts(interrupts)
def write_line(self, line): def write_line(self, line):
self.f.write(line + "\n") self.f.write(line + "\n")

@ -6,7 +6,7 @@ const micro = @import("microzig");
pub const panic = micro.panic; pub const panic = micro.panic;
pub const vector_table = struct { pub const vector_table = struct {
pub fn systick() void { pub fn SysTick() void {
@panic("hit systick!"); @panic("hit systick!");
} }
}; };

Loading…
Cancel
Save