svd field array (#77)

wch-ch32v003
Matt Knight 2 years ago committed by Matt Knight
parent 71a8e27e8e
commit ec84f7eebf

@ -485,6 +485,7 @@ pub fn createField(
/// size is in bits /// size is in bits
size: ?u64 = null, size: ?u64 = null,
enum_id: ?EntityId = null, enum_id: ?EntityId = null,
count: ?u64 = null,
}, },
) !EntityId { ) !EntityId {
assert(db.entityIs("type.register", parent_id)); assert(db.entityIs("type.register", parent_id));
@ -504,6 +505,9 @@ pub fn createField(
if (opts.size) |s| if (opts.size) |s|
try db.addSize(id, s); try db.addSize(id, s);
if (opts.count) |c|
try db.addCount(id, c);
if (opts.enum_id) |enum_id| { if (opts.enum_id) |enum_id| {
assert(db.entityIs("type.enum", enum_id)); assert(db.entityIs("type.enum", enum_id));
if (db.attrs.size.get(enum_id)) |enum_size| if (db.attrs.size.get(enum_id)) |enum_size|

@ -762,12 +762,19 @@ fn writeFields(
while (end < fields.len and fields[end].offset == offset) : (end += 1) {} while (end < fields.len and fields[end].offset == offset) : (end += 1) {}
const next = blk: { const next = blk: {
var ret: ?EntityWithOffsetAndSize = null; var ret: ?EntityWithOffsetAndSize = null;
for (fields[i..end]) |register| { for (fields[i..end]) |field| {
const size = db.attrs.size.get(register.id) orelse unreachable; const size = if (db.attrs.size.get(field.id)) |size|
if (db.attrs.count.get(field.id)) |count|
size * count
else
size
else
unreachable;
if (ret == null or (size < ret.?.size)) if (ret == null or (size < ret.?.size))
ret = .{ ret = .{
.id = register.id, .id = field.id,
.offset = register.offset, .offset = field.offset,
.size = size, .size = size,
}; };
} }
@ -789,7 +796,25 @@ fn writeFields(
if (db.attrs.description.get(next.id)) |description| if (db.attrs.description.get(next.id)) |description|
try writeComment(db.arena.allocator(), description, writer); try writeComment(db.arena.allocator(), description, writer);
if (db.attrs.@"enum".get(fields[i].id)) |enum_id| { if (db.attrs.count.get(fields[i].id)) |count| {
if (db.attrs.@"enum".contains(fields[i].id))
log.warn("TODO: field array with enums", .{});
try writer.print("{s}: packed struct(u{}) {{ ", .{
std.zig.fmtId(name),
next.size,
});
var j: u32 = 0;
while (j < count) : (j += 1) {
if (j > 0)
try writer.writeAll(", ");
try writer.print("u{}", .{next.size / count});
}
try writer.writeAll(" },\n");
} else if (db.attrs.@"enum".get(fields[i].id)) |enum_id| {
if (db.attrs.name.get(enum_id)) |enum_name| { if (db.attrs.name.get(enum_id)) |enum_name| {
try writer.print( try writer.print(
\\{s}: packed union {{ \\{s}: packed union {{
@ -797,14 +822,22 @@ fn writeFields(
\\ value: {s}, \\ value: {s},
\\}}, \\}},
\\ \\
, .{ name, next.size, std.zig.fmtId(enum_name) }); , .{
std.zig.fmtId(name),
next.size,
std.zig.fmtId(enum_name),
});
} else { } else {
try writer.print( try writer.print(
\\{s}: packed union {{ \\{s}: packed union {{
\\ raw: u{}, \\ raw: u{},
\\ value: enum(u{}) {{ \\ value: enum(u{}) {{
\\ \\
, .{ name, next.size, next.size }); , .{
std.zig.fmtId(name),
next.size,
next.size,
});
try writeEnumFields(db, enum_id, writer); try writeEnumFields(db, enum_id, writer);
try writer.writeAll("},\n},\n"); try writer.writeAll("},\n},\n");
} }
@ -1617,6 +1650,90 @@ test "gen.register with count and fields" {
, buffer.items); , buffer.items);
} }
test "gen.field with count, width of one, offset, and padding" {
var db = try Database.init(std.testing.allocator);
defer db.deinit();
const peripheral_id = try db.createPeripheral(.{
.name = "PORTB",
});
const portb_id = try db.createRegister(peripheral_id, .{
.name = "PORTB",
.size = 8,
.offset = 0,
});
_ = try db.createField(portb_id, .{
.name = "TEST_FIELD",
.size = 1,
.offset = 2,
.count = 5,
});
var buffer = std.ArrayList(u8).init(std.testing.allocator);
defer buffer.deinit();
try db.toZig(buffer.writer());
try std.testing.expectEqualStrings(
\\const micro = @import("microzig");
\\const mmio = micro.mmio;
\\
\\pub const types = struct {
\\ pub const PORTB = extern struct {
\\ PORTB: mmio.Mmio(packed struct(u8) {
\\ reserved2: u2,
\\ TEST_FIELD: packed struct(u5) { u1, u1, u1, u1, u1 },
\\ padding: u1,
\\ }),
\\ };
\\};
\\
, buffer.items);
}
test "gen.field with count, multi-bit width, offset, and padding" {
var db = try Database.init(std.testing.allocator);
defer db.deinit();
const peripheral_id = try db.createPeripheral(.{
.name = "PORTB",
});
const portb_id = try db.createRegister(peripheral_id, .{
.name = "PORTB",
.size = 8,
.offset = 0,
});
_ = try db.createField(portb_id, .{
.name = "TEST_FIELD",
.size = 2,
.offset = 2,
.count = 2,
});
var buffer = std.ArrayList(u8).init(std.testing.allocator);
defer buffer.deinit();
try db.toZig(buffer.writer());
try std.testing.expectEqualStrings(
\\const micro = @import("microzig");
\\const mmio = micro.mmio;
\\
\\pub const types = struct {
\\ pub const PORTB = extern struct {
\\ PORTB: mmio.Mmio(packed struct(u8) {
\\ reserved2: u2,
\\ TEST_FIELD: packed struct(u4) { u2, u2 },
\\ padding: u2,
\\ }),
\\ };
\\};
\\
, buffer.items);
}
test "gen.interrupts.avr" { test "gen.interrupts.avr" {
var db = try Database.init(std.testing.allocator); var db = try Database.init(std.testing.allocator);
defer db.deinit(); defer db.deinit();

@ -332,14 +332,14 @@ fn loadCluster(
return error.TodoDimElements; return error.TodoDimElements;
} }
fn getNameWithoutArraySuffix(node: xml.Node) ![]const u8 { fn getNameWithoutSuffix(node: xml.Node, suffix: []const u8) ![]const u8 {
return if (node.getValue("name")) |name| return if (node.getValue("name")) |name|
if (std.mem.endsWith(u8, name, "[%s]")) if (std.mem.endsWith(u8, name, suffix))
name[0 .. name.len - 4] name[0 .. name.len - suffix.len]
else else
name name
else else
error.MissingRegisterName; error.MissingName;
} }
fn loadRegister( fn loadRegister(
@ -348,7 +348,6 @@ fn loadRegister(
parent_id: EntityId, parent_id: EntityId,
) !void { ) !void {
const db = ctx.db; const db = ctx.db;
const register_props = try ctx.deriveRegisterPropertiesFrom(node, parent_id); const register_props = try ctx.deriveRegisterPropertiesFrom(node, parent_id);
const size = register_props.size orelse return error.MissingRegisterSize; const size = register_props.size orelse return error.MissingRegisterSize;
const count: ?u64 = if (try DimElements.parse(node)) |elements| count: { const count: ?u64 = if (try DimElements.parse(node)) |elements| count: {
@ -362,7 +361,7 @@ fn loadRegister(
} else null; } else null;
const id = try db.createRegister(parent_id, .{ const id = try db.createRegister(parent_id, .{
.name = try getNameWithoutArraySuffix(node), .name = try getNameWithoutSuffix(node, "[%s]"),
.description = node.getValue("description"), .description = node.getValue("description"),
.offset = if (node.getValue("addressOffset")) |offset_str| .offset = if (node.getValue("addressOffset")) |offset_str|
try std.fmt.parseInt(u64, offset_str, 0) try std.fmt.parseInt(u64, offset_str, 0)
@ -399,18 +398,25 @@ fn loadField(ctx: *Context, node: xml.Node, register_id: EntityId) !void {
const db = ctx.db; const db = ctx.db;
const bit_range = try BitRange.parse(node); const bit_range = try BitRange.parse(node);
const count: ?u64 = if (try DimElements.parse(node)) |elements| count: {
if (elements.dim_index != null or elements.dim_name != null)
return error.TodoDimElementsExtended;
if (elements.dim_increment != bit_range.width)
return error.DimIncrementSizeMismatch;
break :count elements.dim;
} else null;
const id = try db.createField(register_id, .{ const id = try db.createField(register_id, .{
.name = node.getValue("name") orelse return error.MissingFieldName, .name = try getNameWithoutSuffix(node, "%s"),
.description = node.getValue("description"), .description = node.getValue("description"),
.size = bit_range.width, .size = bit_range.width,
.offset = bit_range.offset, .offset = bit_range.offset,
.count = count,
}); });
errdefer db.destroyEntity(id); errdefer db.destroyEntity(id);
const dim_elements = try DimElements.parse(node);
if (dim_elements != null)
return error.TodoDimElements;
if (node.getValue("access")) |access_str| if (node.getValue("access")) |access_str|
try db.addAccess(id, try parseAccess(access_str)); try db.addAccess(id, try parseAccess(access_str));
@ -421,12 +427,9 @@ fn loadField(ctx: *Context, node: xml.Node, register_id: EntityId) !void {
try ctx.addDerivedEntity(id, derived_from); try ctx.addDerivedEntity(id, derived_from);
// TODO: // TODO:
// dimElementGroup
// modifiedWriteValues // modifiedWriteValues
// writeConstraint // writeConstraint
// readAction // readAction
// enumeratedValues
} }
fn loadEnumeratedValues(ctx: *Context, node: xml.Node, field_id: EntityId) !void { fn loadEnumeratedValues(ctx: *Context, node: xml.Node, field_id: EntityId) !void {
@ -1211,3 +1214,44 @@ test "svd.register with dimElementGroup, suffixed with [%s]" {
const register_id = try db.getEntityIdByName("type.register", "TEST_REGISTER"); const register_id = try db.getEntityIdByName("type.register", "TEST_REGISTER");
try expectAttr(db, "count", 4, register_id); try expectAttr(db, "count", 4, register_id);
} }
test "svd.field with dimElementGroup, suffixed with %s" {
const text =
\\<device>
\\ <name>TEST_DEVICE</name>
\\ <size>32</size>
\\ <access>read-only</access>
\\ <resetValue>0x00000000</resetValue>
\\ <resetMask>0xffffffff</resetMask>
\\ <peripherals>
\\ <peripheral>
\\ <name>TEST_PERIPHERAL</name>
\\ <baseAddress>0x1000</baseAddress>
\\ <registers>
\\ <register>
\\ <name>TEST_REGISTER</name>
\\ <addressOffset>0</addressOffset>
\\ <fields>
\\ <field>
\\ <name>TEST_FIELD%s</name>
\\ <access>read-write</access>
\\ <bitRange>[0:0]</bitRange>
\\ <dim>2</dim>
\\ <dimIncrement>1</dimIncrement>
\\ </field>
\\ </fields>
\\ </register>
\\ </registers>
\\ </peripheral>
\\ </peripherals>
\\</device>
;
var doc = try xml.Doc.fromMemory(text);
var db = try Database.initFromSvd(std.testing.allocator, doc);
defer db.deinit();
// %s is dropped from name, it is redundant
const register_id = try db.getEntityIdByName("type.field", "TEST_FIELD");
try expectAttr(db, "count", 2, register_id);
}

Loading…
Cancel
Save