Skip to content

Commit 42271e9

Browse files
mattniteGuney Saramali
authored andcommitted
ATDF nested register groups (#650)
1 parent 4c330a8 commit 42271e9

File tree

4 files changed

+116
-40
lines changed

4 files changed

+116
-40
lines changed

build.zig

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,16 @@ var port_cache: PortCache = .{};
208208
/// ```
209209
pub fn MicroBuild(port_select: PortSelect) type {
210210
return struct {
211+
builder: *Build,
212+
dep: *Build.Dependency,
213+
core_dep: *Build.Dependency,
214+
drivers_dep: *Build.Dependency,
215+
216+
/// Contains all the ports you selected.
217+
ports: SelectedPorts,
218+
219+
const Self = @This();
220+
211221
const SelectedPorts = blk: {
212222
var fields: []const std.builtin.Type.StructField = &.{};
213223

@@ -234,16 +244,6 @@ pub fn MicroBuild(port_select: PortSelect) type {
234244
});
235245
};
236246

237-
const Self = @This();
238-
239-
builder: *Build,
240-
dep: *Build.Dependency,
241-
core_dep: *Build.Dependency,
242-
drivers_dep: *Build.Dependency,
243-
244-
/// Contains all the ports you selected.
245-
ports: SelectedPorts,
246-
247247
const InitReturnType = blk: {
248248
@setEvalBranchQuota(2000);
249249

tools/regz/src/Database.zig

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -663,6 +663,20 @@ pub fn get_peripheral_by_name(db: *Database, name: []const u8) !?PeripheralID {
663663
return db.get_id_by_name(PeripheralID, name);
664664
}
665665

666+
/// Get the struct ID for a struct decl with `name` in parent struct
667+
pub fn get_struct_decl_id_by_name(db: *Database, parent: StructID, name: []const u8) !StructID {
668+
const query =
669+
\\SELECT struct_id
670+
\\FROM struct_decls
671+
\\WHERE parent_id = ? AND name = ?
672+
;
673+
674+
return db.one(StructID, query, .{
675+
.parent_id = parent,
676+
.name = name,
677+
});
678+
}
679+
666680
pub fn get_struct_decl_by_name(db: *Database, allocator: Allocator, parent: StructID, name: []const u8) !StructDecl {
667681
const query = std.fmt.comptimePrint(
668682
\\SELECT {s}
@@ -945,12 +959,16 @@ pub fn get_nested_struct_fields_with_calculated_size(
945959
const nested_struct_fields = try db.get_nested_struct_fields(allocator, struct_id);
946960
defer allocator.free(nested_struct_fields);
947961

962+
log.debug("nested_struct_fields.len={} struct_id={}", .{ nested_struct_fields.len, struct_id });
963+
948964
var size_cache: std.AutoArrayHashMap(StructID, u64) = .init(allocator);
949965
defer size_cache.deinit();
950966

951967
for (nested_struct_fields) |*nsf| {
952-
if (nsf.size_bytes != null)
968+
if (nsf.size_bytes != null) {
969+
try ret.append(nsf.*);
953970
continue;
971+
}
954972

955973
var depth: u8 = 0;
956974
const size_bytes = try db.recursively_calculate_struct_size(&depth, &size_cache, allocator, nsf.struct_id);

tools/regz/src/atdf.zig

Lines changed: 65 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -273,12 +273,13 @@ fn infer_enum_size(allocator: Allocator, module_node: xml.Node, value_group_node
273273
var field_sizes = std.ArrayList(u64).init(allocator);
274274
defer field_sizes.deinit();
275275

276-
var register_it = module_node.iterate(&.{}, &.{"register"});
276+
var register_it = module_node.iterate(&.{"register-group"}, &.{"register"});
277277
while (register_it.next()) |register_node| {
278278
var bitfield_it = register_node.iterate(&.{}, &.{"bitfield"});
279279
while (bitfield_it.next()) |bitfield_node| {
280280
if (bitfield_node.get_attribute("values")) |values| {
281281
if (std.mem.eql(u8, values, value_group_name)) {
282+
log.debug("found values={s}", .{values});
282283
const mask_str = bitfield_node.get_attribute("mask") orelse continue;
283284
const mask = try std.fmt.parseInt(u64, mask_str, 0);
284285
try field_sizes.append(@popCount(mask));
@@ -288,6 +289,8 @@ fn infer_enum_size(allocator: Allocator, module_node: xml.Node, value_group_node
288289
}
289290
}
290291

292+
log.debug("found field usage count of: {}", .{field_sizes.items.len});
293+
291294
// if all the field sizes are the same, and the max value can fit in there,
292295
// then set the size of the enum. If there are no usages of an enum, then
293296
// assign it the smallest value possible
@@ -305,8 +308,10 @@ fn infer_enum_size(allocator: Allocator, module_node: xml.Node, value_group_node
305308
return error.InconsistentEnumSizes;
306309
}
307310

308-
if (max_value > 0 and (std.math.log2_int(u64, max_value) + 1) > ret.?)
309-
return error.EnumMaxValueTooBig;
311+
if (max_value > 0 and (std.math.log2_int(u64, max_value) + 1) > ret.?) {
312+
log.warn("Uses of this enum are smaller than the calculated size", .{});
313+
return std.math.log2_int(u64, max_value);
314+
}
310315

311316
break :blk @intCast(ret.?);
312317
};
@@ -369,7 +374,7 @@ fn load_module_type(ctx: *Context, node: xml.Node) !void {
369374
// registers. This operation needs to be done in
370375
// `loadModuleInstance()` as well
371376
if (get_inlined_register_group(node, name)) |register_group_node| {
372-
try load_register_group_children(ctx, register_group_node, struct_id);
377+
try load_register_group_children(ctx, register_group_node, peripheral, struct_id);
373378
} else {
374379
var register_group_it = node.iterate(&.{}, &.{"register-group"});
375380
while (register_group_it.next()) |register_group_node|
@@ -407,6 +412,7 @@ fn load_module_interrupt_group_entry(
407412
fn load_register_group_children(
408413
ctx: *Context,
409414
node: xml.Node,
415+
peripheral: PeripheralID,
410416
parent: StructID,
411417
) !void {
412418
var mode_it = node.iterate(&.{}, &.{"mode"});
@@ -416,9 +422,59 @@ fn load_register_group_children(
416422
return err;
417423
};
418424

419-
var register_it = node.iterate(&.{}, &.{ "register", "register-group" });
425+
var register_it = node.iterate(&.{}, &.{"register"});
420426
while (register_it.next()) |register_node|
421427
try load_register(ctx, register_node, parent);
428+
429+
var register_group_it = node.iterate(&.{}, &.{"register-group"});
430+
while (register_group_it.next()) |register_group_node|
431+
try load_nested_register_group(ctx, register_group_node, peripheral, parent);
432+
}
433+
434+
fn load_nested_register_group(
435+
ctx: *Context,
436+
node: xml.Node,
437+
peripheral: PeripheralID,
438+
parent: StructID,
439+
) !void {
440+
const db = ctx.db;
441+
log.debug("load_nested_register_group: peripheral={} parent={}", .{ peripheral, parent });
442+
443+
validate_attrs(node, &.{
444+
"name",
445+
"name-in-module",
446+
"offset",
447+
"size",
448+
"count",
449+
"caption",
450+
});
451+
452+
const name = node.get_attribute("name") orelse return error.MissingRegisterName;
453+
const name_in_module = node.get_attribute("name-in-module") orelse return error.MissingNameInModule;
454+
455+
const peripheral_struct_id = try db.get_peripheral_struct(peripheral);
456+
log.debug(" peripheral_struct_id={}", .{peripheral_struct_id});
457+
const struct_id = try db.get_struct_decl_id_by_name(peripheral_struct_id, name_in_module);
458+
log.debug(" struct_id={}", .{struct_id});
459+
460+
try db.add_nested_struct_field(parent, .{
461+
.name = name,
462+
.struct_id = struct_id,
463+
.offset_bytes = if (node.get_attribute("offset")) |offset_str|
464+
try std.fmt.parseInt(u64, offset_str, 0)
465+
else
466+
return error.MissingRegisterOffset,
467+
.description = node.get_attribute("caption"),
468+
469+
.size_bytes = if (node.get_attribute("size")) |size_str|
470+
try std.fmt.parseInt(u64, size_str, 0)
471+
else
472+
null,
473+
.count = if (node.get_attribute("count")) |count_str|
474+
try std.fmt.parseInt(u64, count_str, 0)
475+
else
476+
null,
477+
});
422478
}
423479

424480
fn infer_register_group_offset(ctx: *Context, node: xml.Node, struct_id: StructID) !void {
@@ -439,34 +495,16 @@ fn infer_register_group_offset(ctx: *Context, node: xml.Node, struct_id: StructI
439495

440496
// loads a register group which is under a peripheral or under another
441497
// register-group
442-
//
443-
// TODO: implement nested register groups
444498
fn load_register_group(ctx: *Context, node: xml.Node, parent: PeripheralID) !void {
445499
const db = ctx.db;
446500

447-
//switch (parent) {
448-
// .peripheral =>
449-
450501
validate_attrs(node, &.{
451502
"name",
452503
"caption",
453504
"aligned",
454505
"section",
455506
"size",
456507
});
457-
// .register_group => validate_attrs(node, &.{
458-
// "name",
459-
// "modes",
460-
// "size",
461-
// "name-in-module",
462-
// "caption",
463-
// "count",
464-
// "start-index",
465-
// "offset",
466-
// }),
467-
//}
468-
469-
// TODO: for now just making register groups into structs.
470508

471509
const parent_struct_id = try db.get_peripheral_struct(parent);
472510
const struct_id = try db.create_nested_struct(parent_struct_id, .{
@@ -479,7 +517,7 @@ fn load_register_group(ctx: *Context, node: xml.Node, parent: PeripheralID) !voi
479517
});
480518

481519
try infer_register_group_offset(ctx, node, struct_id);
482-
try load_register_group_children(ctx, node, struct_id);
520+
try load_register_group_children(ctx, node, parent, struct_id);
483521
// TODO: infer register group size?
484522
// Do register groups ever operate as just namespaces?
485523

@@ -786,6 +824,8 @@ fn load_enum(
786824
.size_bits = size_bits,
787825
});
788826

827+
log.debug("{}: name={s} inferred_size={}", .{ enum_id, name, size_bits });
828+
789829
var value_it = node.iterate(&.{}, &.{"value"});
790830
while (value_it.next()) |value_node|
791831
load_enum_field(ctx, value_node, enum_id) catch {};
@@ -862,6 +902,7 @@ fn load_module_instance(
862902

863903
const struct_id = try ctx.db.get_peripheral_struct(peripheral_id);
864904

905+
//
865906
// register-group never has an offset in a module, so we can safely assume
866907
// that they're used as variants of a peripheral, and never used like
867908
// clusters in SVD.

tools/regz/src/gen.zig

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,12 +1035,16 @@ fn write_nested_struct_field(db: *Database, arena: Allocator, nsf: *const Nested
10351035
try write_doc_comment(arena, offset_str, writer);
10361036

10371037
try writer.print("{}: ", .{std.zig.fmtId(nsf.name)});
1038+
var array_prefix_buf: [80]u8 = undefined;
1039+
const array_prefix: []const u8 = if (nsf.count) |count|
1040+
try std.fmt.bufPrint(&array_prefix_buf, "[{}]", .{count})
1041+
else
1042+
"";
1043+
try writer.print("{s}", .{array_prefix});
10381044

10391045
// TODO: if it's a struct decl then refer to it by name
10401046
if (try db.get_struct_decl_by_struct_id(arena, nsf.struct_id)) |struct_decl| {
1041-
if (struct_decl.parent_id != nsf.parent_id)
1042-
return error.TodoDifferentParentStructDecl;
1043-
1047+
// TODO full reference?
10441048
try writer.print("{},\n", .{std.zig.fmtId(struct_decl.name)});
10451049
} else {
10461050
try write_struct(db, arena, null, nsf.struct_id, writer);
@@ -1056,6 +1060,7 @@ fn write_registers_and_nested_structs_base(
10561060
nested_struct_fields: []NestedStructField,
10571061
out_writer: anytype,
10581062
) !void {
1063+
log.debug("registers.len={} nested_struct_fields.len={}", .{ registers.len, nested_struct_fields.len });
10591064
var it: StructFieldIterator = .init(registers, nested_struct_fields);
10601065

10611066
var buffer = std.ArrayList(u8).init(arena);
@@ -1186,6 +1191,7 @@ fn write_fields(
11861191
var offset: u64 = 0;
11871192

11881193
for (expanded_fields.items) |field| {
1194+
log.debug("next field: offset={} field.offset_bits={}", .{ offset, field.offset_bits });
11891195
if (offset > field.offset_bits) {
11901196
// It's possible there are fields that overlap so
11911197
// we're going to filter out some fields so there's no overlap.
@@ -1217,7 +1223,12 @@ fn write_fields(
12171223

12181224
if (field.enum_id) |enum_id| {
12191225
const e = try db.get_enum(arena, enum_id);
1220-
if (e.name) |enum_name| {
1226+
if (e.size_bits != field.size_bits) {
1227+
log.warn("{}: fails to match the size of {s}, with sizes of {} and {} respectively. Not assigning type.", .{
1228+
enum_id, field.name, e.size_bits, field.size_bits,
1229+
});
1230+
try writer.print("{}: u{},\n", .{ std.zig.fmtId(field.name), field.size_bits });
1231+
} else if (e.name) |enum_name| {
12211232
if (e.struct_id == null or try db.enum_has_name_collision(enum_id)) {
12221233
try writer.print(
12231234
\\{}: enum(u{}) {{
@@ -1254,12 +1265,18 @@ fn write_fields(
12541265
try writer.print("{}: u{},\n", .{ std.zig.fmtId(field.name), field.size_bits });
12551266
}
12561267

1268+
log.debug("adding size bits to offset: offset={} field.size_bits={}", .{ offset, field.size_bits });
12571269
offset += field.size_bits;
12581270
}
12591271

1272+
log.debug("before padding: offset={} register_size_bits={}", .{ offset, register_size_bits });
12601273
assert(offset <= register_size_bits);
1261-
if (offset < register_size_bits)
1274+
if (offset < register_size_bits) {
1275+
log.debug("writing padding", .{});
12621276
try writer.print("padding: u{} = 0,\n", .{register_size_bits - offset});
1277+
} else {
1278+
log.debug("No padding", .{});
1279+
}
12631280

12641281
try out_writer.writeAll(buffer.items);
12651282
}

0 commit comments

Comments
 (0)