fix mmio int generation (#25)

wch-ch32v003
Matt Knight 2 years ago committed by Matt Knight
parent 780a75268f
commit 6f4850dab7

@ -489,7 +489,6 @@ fn loadNestedClusters(
pub fn initFromAtdf(allocator: Allocator, doc: *xml.Doc) !Database {
const root_element: *xml.Node = xml.docGetRootElement(doc) orelse return error.NoRoot;
const tools_node = xml.findNode(root_element, "avr-tools-device-file") orelse return error.NoToolsNode;
var regs_start_addr: usize = 0;
var peripheral_instances = std.StringHashMap(void).init(allocator);
defer peripheral_instances.deinit();
@ -543,33 +542,6 @@ pub fn initFromAtdf(allocator: Allocator, doc: *xml.Doc) !Database {
};
const device_nodes: *xml.Node = device_it.?.children orelse continue;
regs_start_addr = if (xml.findNode(device_nodes, "address-spaces")) |address_spaces_node| blk: {
var ret: ?usize = null;
var address_space_it: ?*xml.Node = xml.findNode(address_spaces_node.children.?, "address-space");
while (address_space_it != null) : (address_space_it = xml.findNode(address_space_it.?.next, "address-space")) {
const address_space_nodes: *xml.Node = address_space_it.?.children orelse continue;
var memory_segment_it: ?*xml.Node = xml.findNode(address_space_nodes, "memory-segment");
while (memory_segment_it != null) : (memory_segment_it = xml.findNode(memory_segment_it.?.next, "memory-segment")) {
const memory_type = xml.getAttribute(memory_segment_it, "type") orelse continue;
if (std.mem.eql(u8, "regs", memory_type)) {
if (ret != null) {
std.log.err("multiple register memory segments found, no idea what to do, please cut a ticket: https://github.com/ZigEmbeddedGroup/regz", .{});
return error.Explained;
} else if (xml.getAttribute(memory_segment_it, "start")) |addr_str| {
ret = try std.fmt.parseInt(usize, addr_str, 0);
}
}
}
}
if (ret) |start_address| {
break :blk start_address;
} else {
std.log.err("failed to determine the start address for registers", .{});
return error.Explained;
}
} else unreachable;
if (xml.findNode(device_nodes, "peripherals")) |peripherals_node| {
var module_it: ?*xml.Node = xml.findNode(peripherals_node.children.?, "module");
while (module_it != null) : (module_it = xml.findNode(module_it.?.next, "module")) {
@ -668,14 +640,21 @@ pub fn initFromAtdf(allocator: Allocator, doc: *xml.Doc) !Database {
if (!peripheral_instances.contains(group_name))
continue;
const register_group_offset = try xml.parseIntForKey(usize, db.gpa, register_group_nodes, "offset");
const peripheral_idx = @intCast(PeripheralIndex, db.peripherals.items.len);
try db.peripherals.append(db.gpa, try atdf.parsePeripheral(&db.arena, register_group_it.?));
const reg_begin_idx = @intCast(RegisterIndex, db.registers.items.len);
var register_it: ?*xml.Node = xml.findNode(register_group_nodes, "register");
while (register_it != null) : (register_it = xml.findNode(register_it.?.next, "register")) {
const register = try atdf.parseRegister(&db.arena, register_it.?, register_group_offset, register_it.?.children != null);
const register_idx = @intCast(RegisterIndex, db.registers.items.len);
try db.registers.append(db.gpa, try atdf.parseRegister(&db.arena, register_it.?, regs_start_addr, register_it.?.children != null));
try db.registers.append(db.gpa, register);
if (register.size) |size|
try db.register_properties.register.size.put(db.gpa, register_idx, size);
const register_nodes: *xml.Node = register_it.?.children orelse continue;
const field_begin_idx = @intCast(FieldIndex, db.fields.items.len);
@ -1096,19 +1075,60 @@ fn genZigSingleRegister(
} else {
switch (nesting) {
.namespaced => if (has_base_addr)
try writer.print("pub const {s} = @intToPtr(*volatile {s}u{}, base_address + 0x{x});\n", .{
std.zig.fmtId(name),
array_prefix,
width,
addr_offset,
})
else
try writer.print("pub const {s} = @intToPtr(*volatile {s}u{}, 0x{x});\n", .{
std.zig.fmtId(name),
array_prefix,
width,
addr_offset,
}),
if (width >= 8 and std.math.isPowerOfTwo(width))
try writer.print("pub const {s} = @intToPtr(*volatile {s}u{}, base_address + 0x{x});\n", .{
std.zig.fmtId(name),
array_prefix,
width,
addr_offset,
})
else {
const reg_width = reg_width: {
var reg_width: usize = 8;
while (reg_width < width) : (reg_width *= 2) {
if (reg_width > 128)
return error.TooBig; // artificial limit, probably something weird going on
}
break :reg_width reg_width;
};
try writer.print("pub const {s} = @intToPtr(*volatile {s}MmioInt({}, u{}), base_address + 0x{x});\n", .{
std.zig.fmtId(name),
array_prefix,
reg_width,
width,
addr_offset,
});
}
else {
if (width >= 8 and std.math.isPowerOfTwo(width))
try writer.print("pub const {s} = @intToPtr(*volatile {s}u{}, 0x{x});\n", .{
std.zig.fmtId(name),
array_prefix,
width,
addr_offset,
})
else {
const reg_width = reg_width: {
var reg_width: usize = 8;
while (reg_width < width) : (reg_width *= 2) {
if (reg_width > 128)
return error.TooBig; // artificial limit, probably something weird going on
}
break :reg_width reg_width;
};
try writer.print("pub const {s} = @intToPtr(*volatile {s}MmioInt({}, u{}), 0x{x});\n", .{
std.zig.fmtId(name),
array_prefix,
reg_width,
width,
addr_offset,
});
}
},
.contained => try writer.print("{s}: {s}u{},\n", .{
std.zig.fmtId(name),
array_prefix,
@ -1441,8 +1461,10 @@ pub fn getRegister(
db: Database,
reg_idx: RegisterIndex,
) !Register {
const register = db.registers.items[reg_idx];
if (reg_idx >= db.registers.items.len)
return error.NotFound;
const register = db.registers.items[reg_idx];
var clusters = std.ArrayListUnmanaged(ClusterIndex){};
defer clusters.deinit(db.gpa);
@ -1544,3 +1566,38 @@ const useless_descriptions = std.ComptimeStringMap(void, .{
const useless_field_names = std.ComptimeStringMap(void, .{
.{"RESERVED"},
});
pub fn format(
db: Database,
comptime fmt: []const u8,
options: std.fmt.FormatOptions,
writer: anytype,
) !void {
_ = db;
_ = options;
_ = fmt;
try writer.writeAll("Regz Database:\n");
if (db.interrupts.items.len > 0) {
try writer.writeAll(" Interrupts:\n");
for (db.interrupts.items) |interrupt|
try writer.print(" {}\n", .{interrupt});
}
if (db.peripherals.items.len > 0) {
try writer.writeAll(" Peripherals:\n");
for (db.peripherals.items) |peripheral, i|
try writer.print(" {}: {}\n", .{ i, peripheral });
}
if (db.registers.items.len > 0) {
try writer.writeAll(" Registers:\n");
for (db.registers.items) |register, i|
try writer.print(" {}: {}\n", .{ i, register });
}
if (db.fields.items.len > 0) {
try writer.writeAll(" Fields:\n");
for (db.fields.items) |field, i|
try writer.print(" {}: {}\n", .{ i, field });
}
}

@ -1,4 +1,20 @@
const std = @import("std");
name: []const u8,
version: ?[]const u8,
description: ?[]const u8,
base_addr: ?usize,
pub fn format(
peripheral: @This(),
comptime fmt: []const u8,
options: std.fmt.FormatOptions,
writer: anytype,
) !void {
_ = fmt;
_ = options;
try writer.print("{s}: {s}", .{
peripheral.name,
peripheral.description,
});
}

@ -1,3 +1,5 @@
const std = @import("std");
name: []const u8,
description: ?[]const u8,
addr_offset: usize,
@ -5,3 +7,19 @@ size: ?usize,
access: ?@import("svd.zig").Access,
reset_value: ?u64,
reset_mask: ?u64,
pub fn format(
register: @This(),
comptime fmt: []const u8,
options: std.fmt.FormatOptions,
writer: anytype,
) !void {
_ = fmt;
_ = options;
try writer.print("0x{x} -> {s}: size={}, {s}", .{
register.addr_offset,
register.name,
register.size,
register.description,
});
}

@ -24,7 +24,12 @@ pub fn parsePeripheral(arena: *ArenaAllocator, node: *xml.Node) !Peripheral {
};
}
pub fn parseRegister(arena: *ArenaAllocator, node: *xml.Node, regs_start_addr: usize, has_fields: bool) !Register {
pub fn parseRegister(
arena: *ArenaAllocator,
node: *xml.Node,
register_group_offset: ?usize,
has_fields: bool,
) !Register {
const allocator = arena.allocator();
return Register{
.name = try allocator.dupe(u8, xml.getAttribute(node, "name") orelse return error.NoName),
@ -32,10 +37,13 @@ pub fn parseRegister(arena: *ArenaAllocator, node: *xml.Node, regs_start_addr: u
try allocator.dupe(u8, caption)
else
null,
.addr_offset = if (xml.getAttribute(node, "offset")) |reg_offset_str|
regs_start_addr + try std.fmt.parseInt(usize, reg_offset_str, 0)
else
return error.NoAddrOffset,
.addr_offset = if (xml.getAttribute(node, "offset")) |reg_offset_str| addr_offset: {
const reg_offset = try std.fmt.parseInt(usize, reg_offset_str, 0);
break :addr_offset if (register_group_offset) |group_offset|
group_offset + reg_offset
else
reg_offset;
} else return error.NoAddrOffset,
.size = if (xml.getAttribute(node, "size")) |size_str| blk: {
const full_size = 8 * try std.fmt.parseInt(usize, size_str, 0);
if (!has_fields) {

@ -1,3 +1,46 @@
test "atdf empty" {
// please remove and do a real test
const std = @import("std");
const xml = @import("xml");
const Database = @import("Database");
const allocator = std.testing.allocator;
const expectEqual = std.testing.expectEqual;
pub fn initDbFromAtdf(text: []const u8) !Database {
const doc: *xml.Doc = try xml.readFromMemory(text);
defer xml.freeDoc(doc);
return try Database.initFromAtdf(allocator, doc);
}
test "correctly generate mmioInt: https://github.com/ZigEmbeddedGroup/regz/issues/6" {
var db = try initDbFromAtdf(
\\<avr-tools-device-file>
\\ <devices>
\\ <device name="ATmega328P" architecture="AVR8" family="megaAVR">
\\ <peripherals>
\\ <module name="USART">
\\ <instance name="USART0" caption="USART">
\\ <register-group name="USART0" name-in-module="USART0" offset="0x00" address-space="data" caption="USART"/>
\\ </instance>
\\ </module>
\\ </peripherals>
\\ </device>
\\ </devices>
\\ <modules>
\\ <module caption="USART" name="USART">
\\ <register-group caption="USART" name="USART0">
\\ <register caption="USART Baud Rate Register Bytes" name="UBRR0" offset="0xC4" size="2" mask="0x0FFF"/>
\\ </register-group>
\\ </module>
\\ </modules>
\\</avr-tools-device-file>
\\
);
defer db.deinit();
const register_idx = 0;
const register = try db.getRegister(register_idx);
// should be 12 and not 16 due to the mask
try expectEqual(@as(usize, 12), register.size.?);
}

Loading…
Cancel
Save