impl vector_table generation for wch ch32

wch-ch32v003
akiroz 2 months ago
parent b5d657a009
commit 263528061d
No known key found for this signature in database
GPG Key ID: 8A5957C4A2F68ACC

@ -38,6 +38,9 @@ pub const chips = struct {
.svd = path("/src/chips/CH32V00xxx.svd"), .svd = path("/src/chips/CH32V00xxx.svd"),
}, },
}, },
.hal = .{
.root_source_file = path("/src/hals/CH32V003xx.zig"),
},
}; };
}; };

@ -10,6 +10,5 @@
"build.zig", "build.zig",
"build.zig.zon", "build.zig.zon",
"src", "src",
"test",
}, },
} }

@ -5,6 +5,14 @@
<name>CH32V00xxx</name> <name>CH32V00xxx</name>
<version>1.2</version> <version>1.2</version>
<description>CH32V00xxx View File</description> <description>CH32V00xxx View File</description>
<cpu>
<name>QINGKEV2</name>
<revision>r0p0</revision>
<endian>little</endian>
<mpuPresent>false</mpuPresent>
<fpuPresent>false</fpuPresent>
<nvicPrioBits>2</nvicPrioBits>
</cpu>
<!--Bus Interface Properties--> <!--Bus Interface Properties-->
<!--RISC-V is byte addressable--> <!--RISC-V is byte addressable-->

@ -1,6 +1,7 @@
const std = @import("std"); const std = @import("std");
const root = @import("root"); const root = @import("root");
const microzig = @import("microzig"); const microzig = @import("microzig");
const assert = std.debug.assert;
pub fn enable_interrupts() void { pub fn enable_interrupts() void {
asm volatile ("csrsi mstatus, 0b1000"); asm volatile ("csrsi mstatus, 0b1000");
@ -30,10 +31,13 @@ pub const startup_logic = struct {
: :
: [eos] "r" (@as(u32, microzig.config.end_of_stack)), : [eos] "r" (@as(u32, microzig.config.end_of_stack)),
); );
root.initialize_system_memories(); root.initialize_system_memories();
asm volatile ("csrsi 0x804, 0b111"); // INTSYSCR: enable EABI + Interrupt nesting + HPE asm volatile ("csrsi 0x804, 0b111"); // INTSYSCR: enable EABI + Interrupt nesting + HPE
asm volatile ("csrsi mtvec, 0b11"); // mtvec: absolute address + vector table mode asm volatile ("csrsi mtvec, 0b11"); // mtvec: absolute address + vector table mode
microzig.cpu.enable_interrupts(); microzig.cpu.enable_interrupts();
microzig_main(); microzig_main();
} }
@ -45,3 +49,14 @@ pub const startup_logic = struct {
pub fn export_startup_logic() void { pub fn export_startup_logic() void {
@export(startup_logic._start, .{ .name = "_start" }); @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;
};

@ -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
}

@ -3,7 +3,8 @@ const MicroZig = @import("microzig/build");
const ch32 = @import("microzig/bsp/wch/ch32"); const ch32 = @import("microzig/bsp/wch/ch32");
const available_examples = [_]Example{ 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 { pub fn build(b: *std.Build) void {

@ -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 });
}
}

@ -120,6 +120,9 @@ pub const Arch = enum {
// mips // mips
mips, mips,
// riscv
qingke_v2,
pub fn to_string(arch: Arch) []const u8 { pub fn to_string(arch: Arch) []const u8 {
return inline for (@typeInfo(Arch).Enum.fields) |field| { return inline for (@typeInfo(Arch).Enum.fields) |field| {
if (@field(Arch, field.name) == arch) if (@field(Arch, field.name) == arch)
@ -176,6 +179,13 @@ pub const Arch = enum {
else => false, 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 // not sure how to communicate the *_once values in generated code

@ -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");
}

@ -9,6 +9,7 @@ const EntitySet = Database.EntitySet;
const arm = @import("arch/arm.zig"); const arm = @import("arch/arm.zig");
const avr = @import("arch/avr.zig"); const avr = @import("arch/avr.zig");
const riscv = @import("arch/riscv.zig");
const log = std.log.scoped(.gen); const log = std.log.scoped(.gen);
@ -232,6 +233,8 @@ fn write_vector_table(
try arm.write_interrupt_vector(db, device_id, writer) try arm.write_interrupt_vector(db, device_id, writer)
else if (arch.is_avr()) else if (arch.is_avr())
try avr.write_interrupt_vector(db, device_id, writer) 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) else if (arch == .unknown)
return return
else else

@ -215,6 +215,8 @@ fn arch_from_str(str: []const u8) Database.Arch {
.cortex_a57 .cortex_a57
else if (std.mem.eql(u8, "CA72", str)) else if (std.mem.eql(u8, "CA72", str))
.cortex_a72 .cortex_a72
else if (std.mem.eql(u8, "QINGKEV2", str))
.qingke_v2
else else
.unknown; .unknown;
} }

Loading…
Cancel
Save