From 263528061d919ad30ec8b229424dab3c5a0ab787 Mon Sep 17 00:00:00 2001 From: akiroz Date: Fri, 19 Jul 2024 20:45:56 +0900 Subject: [PATCH] impl vector_table generation for wch ch32 --- bsp/wch/ch32/build.zig | 3 + bsp/wch/ch32/build.zig.zon | 1 - bsp/wch/ch32/src/chips/CH32V00xxx.svd | 8 +++ bsp/wch/ch32/src/cpus/wch_qingke_v2.zig | 15 ++++ bsp/wch/ch32/src/hals/CH32V003xx.zig | 24 +++++++ examples/wch/ch32/build.zig | 3 +- examples/wch/ch32/src/blinky.zig | 15 ++++ tools/regz/src/Database.zig | 10 +++ tools/regz/src/arch/riscv.zig | 95 +++++++++++++++++++++++++ tools/regz/src/gen.zig | 3 + tools/regz/src/svd.zig | 2 + 11 files changed, 177 insertions(+), 2 deletions(-) create mode 100644 bsp/wch/ch32/src/hals/CH32V003xx.zig create mode 100644 examples/wch/ch32/src/blinky.zig create mode 100644 tools/regz/src/arch/riscv.zig diff --git a/bsp/wch/ch32/build.zig b/bsp/wch/ch32/build.zig index 673fa89..1c5e564 100644 --- a/bsp/wch/ch32/build.zig +++ b/bsp/wch/ch32/build.zig @@ -38,6 +38,9 @@ pub const chips = struct { .svd = path("/src/chips/CH32V00xxx.svd"), }, }, + .hal = .{ + .root_source_file = path("/src/hals/CH32V003xx.zig"), + }, }; }; diff --git a/bsp/wch/ch32/build.zig.zon b/bsp/wch/ch32/build.zig.zon index 84eae81..a334684 100644 --- a/bsp/wch/ch32/build.zig.zon +++ b/bsp/wch/ch32/build.zig.zon @@ -10,6 +10,5 @@ "build.zig", "build.zig.zon", "src", - "test", }, } diff --git a/bsp/wch/ch32/src/chips/CH32V00xxx.svd b/bsp/wch/ch32/src/chips/CH32V00xxx.svd index 8eac916..f32e344 100644 --- a/bsp/wch/ch32/src/chips/CH32V00xxx.svd +++ b/bsp/wch/ch32/src/chips/CH32V00xxx.svd @@ -5,6 +5,14 @@ CH32V00xxx 1.2 CH32V00xxx View File + + QINGKEV2 + r0p0 + little + false + false + 2 + diff --git a/bsp/wch/ch32/src/cpus/wch_qingke_v2.zig b/bsp/wch/ch32/src/cpus/wch_qingke_v2.zig index 6a18dc1..61c3e4d 100644 --- a/bsp/wch/ch32/src/cpus/wch_qingke_v2.zig +++ b/bsp/wch/ch32/src/cpus/wch_qingke_v2.zig @@ -1,6 +1,7 @@ const std = @import("std"); const root = @import("root"); const microzig = @import("microzig"); +const assert = std.debug.assert; pub fn enable_interrupts() void { asm volatile ("csrsi mstatus, 0b1000"); @@ -30,10 +31,13 @@ pub const startup_logic = struct { : : [eos] "r" (@as(u32, microzig.config.end_of_stack)), ); + root.initialize_system_memories(); + asm volatile ("csrsi 0x804, 0b111"); // INTSYSCR: enable EABI + Interrupt nesting + HPE asm volatile ("csrsi mtvec, 0b11"); // mtvec: absolute address + vector table mode microzig.cpu.enable_interrupts(); + microzig_main(); } @@ -45,3 +49,14 @@ pub const startup_logic = struct { pub fn export_startup_logic() void { @export(startup_logic._start, .{ .name = "_start" }); } + +const VectorTable = microzig.chip.VectorTable; +pub const vector_table: VectorTable = blk: { + var tmp: VectorTable = .{}; + if (@hasDecl(root, "microzig_options")) { + for (@typeInfo(root.VectorTableOptions).Struct.fields) |field| + @field(tmp, field.name) = @field(root.microzig_options.interrupts, field.name); + } + + break :blk tmp; +}; diff --git a/bsp/wch/ch32/src/hals/CH32V003xx.zig b/bsp/wch/ch32/src/hals/CH32V003xx.zig new file mode 100644 index 0000000..aa9f58d --- /dev/null +++ b/bsp/wch/ch32/src/hals/CH32V003xx.zig @@ -0,0 +1,24 @@ +const std = @import("std"); +const mz = @import("microzig"); +const periph = mz.chip.peripherals; + +const RCC = periph.RCC; +const FLASH = periph.FLASH; + +pub fn rcc_init_hsi_pll() void { + const CFG0_PLL_TRIM: *u8 = @ptrFromInt(0x1FFFF7D4); // Factory HSI clock trim value + if (CFG0_PLL_TRIM.* != 0xFF) { + RCC.CTLR.modify(.{ .HSITRIM = @as(u5, @truncate(CFG0_PLL_TRIM.*)) }); + } + + FLASH.ACTLR.modify(.{ .LATENCY = 1 }); // Flash wait state 1 for 48MHz clock + + RCC.CFGR0.modify(.{ + .PLLSRC = 0, // HSI + .HPRE = 0, // Prescaler off + }); + RCC.CTLR.modify(.{ .PLLON = 1 }); + while (RCC.CTLR.read().PLLRDY != 1) {} + RCC.CFGR0.modify(.{ .SW = 0b10 }); // Select PLL clock source + while (RCC.CFGR0.read().SWS != 0b10) {} // Spin until PLL selected +} diff --git a/examples/wch/ch32/build.zig b/examples/wch/ch32/build.zig index ec694a8..f80b2b3 100644 --- a/examples/wch/ch32/build.zig +++ b/examples/wch/ch32/build.zig @@ -3,7 +3,8 @@ const MicroZig = @import("microzig/build"); const ch32 = @import("microzig/bsp/wch/ch32"); const available_examples = [_]Example{ - .{ .target = ch32.chips.ch32v003xx, .name = "ch32v003xx", .file = "src/empty.zig" }, + .{ .target = ch32.chips.ch32v003xx, .name = "ch32v003xx_empty", .file = "src/empty.zig" }, + .{ .target = ch32.chips.ch32v003xx, .name = "ch32v003xx_blinky", .file = "src/blinky.zig" }, }; pub fn build(b: *std.Build) void { diff --git a/examples/wch/ch32/src/blinky.zig b/examples/wch/ch32/src/blinky.zig new file mode 100644 index 0000000..cd26260 --- /dev/null +++ b/examples/wch/ch32/src/blinky.zig @@ -0,0 +1,15 @@ +const std = @import("std"); +const mz = @import("microzig"); +const periph = mz.chip.peripherals; + +pub fn main() !void { + mz.hal.rcc_init_hsi_pll(); + periph.RCC.APB2PCENR.modify(.{ .IOPCEN = 1 }); + periph.GPIOC.CFGLR.modify(.{ .CNF1 = 0b00, .MODE1 = 0b11 }); + + var on: u1 = 0; + while (true) { + on ^= 1; + periph.GPIOC.OUTDR.modify(.{ .ODR1 = on }); + } +} diff --git a/tools/regz/src/Database.zig b/tools/regz/src/Database.zig index a31f548..e81585b 100644 --- a/tools/regz/src/Database.zig +++ b/tools/regz/src/Database.zig @@ -120,6 +120,9 @@ pub const Arch = enum { // mips mips, + // riscv + qingke_v2, + pub fn to_string(arch: Arch) []const u8 { return inline for (@typeInfo(Arch).Enum.fields) |field| { if (@field(Arch, field.name) == arch) @@ -176,6 +179,13 @@ pub const Arch = enum { else => false, }; } + + pub fn is_riscv(arch: Arch) bool { + return switch (arch) { + .qingke_v2 => true, + else => false, + }; + } }; // not sure how to communicate the *_once values in generated code diff --git a/tools/regz/src/arch/riscv.zig b/tools/regz/src/arch/riscv.zig new file mode 100644 index 0000000..c203a2f --- /dev/null +++ b/tools/regz/src/arch/riscv.zig @@ -0,0 +1,95 @@ +//! codegen specific to riscv +const std = @import("std"); +const assert = std.debug.assert; + +const Database = @import("../Database.zig"); +const Arch = Database.Arch; +const EntityId = Database.EntityId; + +const gen = @import("../gen.zig"); +const InterruptWithIndexAndName = @import("InterruptWithIndexAndName.zig"); + +const log = std.log.scoped(.@"gen.riscv"); + +pub fn write_interrupt_vector( + db: Database, + device_id: EntityId, + writer: anytype, +) !void { + assert(db.entity_is("instance.device", device_id)); + const arch = db.instances.devices.get(device_id).?.arch; + assert(arch.is_riscv()); + + try writer.writeAll( + \\pub const VectorTable = extern struct { + \\ const Handler = micro.interrupt.Handler; + \\ const unhandled = micro.interrupt.unhandled; + \\ + ); + + var index: i32 = 0; + + if (arch == .qingke_v2) { // CPU specific vectors + try writer.writeAll( + \\ reserved1: [1]u32 = undefined, + \\ NMI: Handler = unhandled, + \\ EXC: Handler = unhandled, + \\ reserved4: [8]u32 = undefined, + \\ SysTick: Handler = unhandled, + \\ reserved13: [1]u32 = undefined, + \\ SWI: Handler = unhandled, + \\ reserved15: [1]u32 = undefined, + \\ + ); + index = 16; + } + + if (db.children.interrupts.get(device_id)) |interrupt_set| { + var interrupts = std.ArrayList(InterruptWithIndexAndName).init(db.gpa); + defer interrupts.deinit(); + + var it = interrupt_set.iterator(); + while (it.next()) |entry| { + const interrupt_id = entry.key_ptr.*; + const interrupt_index = db.instances.interrupts.get(interrupt_id).?; + const name = db.attrs.name.get(interrupt_id) orelse continue; + + try interrupts.append(.{ + .id = interrupt_id, + .name = name, + .index = interrupt_index, + }); + } + + std.sort.insertion( + InterruptWithIndexAndName, + interrupts.items, + {}, + InterruptWithIndexAndName.less_than, + ); + + for (interrupts.items) |interrupt| { + if (index < interrupt.index) { + try writer.print("reserved{}: [{}]u32 = undefined,\n", .{ + index, + interrupt.index - index, + }); + index = interrupt.index; + } else if (index > interrupt.index) { + log.warn("skipping interrupt: {s}", .{interrupt.name}); + continue; + } + + if (db.attrs.description.get(interrupt.id)) |description| + try gen.write_comment(db.gpa, description, writer); + + try writer.print("{}: Handler = unhandled,\n", .{ + std.zig.fmtId(interrupt.name), + }); + + index += 1; + } + } + + try writer.writeAll("};\n\n"); +} diff --git a/tools/regz/src/gen.zig b/tools/regz/src/gen.zig index 93b7f1c..17d6756 100644 --- a/tools/regz/src/gen.zig +++ b/tools/regz/src/gen.zig @@ -9,6 +9,7 @@ const EntitySet = Database.EntitySet; const arm = @import("arch/arm.zig"); const avr = @import("arch/avr.zig"); +const riscv = @import("arch/riscv.zig"); const log = std.log.scoped(.gen); @@ -232,6 +233,8 @@ fn write_vector_table( try arm.write_interrupt_vector(db, device_id, writer) else if (arch.is_avr()) try avr.write_interrupt_vector(db, device_id, writer) + else if (arch.is_riscv()) + try riscv.write_interrupt_vector(db, device_id, writer) else if (arch == .unknown) return else diff --git a/tools/regz/src/svd.zig b/tools/regz/src/svd.zig index 822c44b..94fe3c5 100644 --- a/tools/regz/src/svd.zig +++ b/tools/regz/src/svd.zig @@ -215,6 +215,8 @@ fn arch_from_str(str: []const u8) Database.Arch { .cortex_a57 else if (std.mem.eql(u8, "CA72", str)) .cortex_a72 + else if (std.mem.eql(u8, "QINGKEV2", str)) + .qingke_v2 else .unknown; }