From 2eb508c31835686acc9abd0786c3e9fd39692cc8 Mon Sep 17 00:00:00 2001 From: Matt Knight Date: Wed, 18 May 2022 00:12:05 -0700 Subject: [PATCH] Register properties size (#21) * snapshot * size from register properties now passes tests * finish moving to named index types --- tools/regz/src/Database.zig | 298 ++++++++++++++++++++++++++---------- tools/regz/src/Register.zig | 2 +- tools/regz/src/svd.zig | 15 +- tools/regz/tests/svd.zig | 167 +++++++++++++++++++- 4 files changed, 393 insertions(+), 89 deletions(-) diff --git a/tools/regz/src/Database.zig b/tools/regz/src/Database.zig index 1771cd2..8e44dcf 100644 --- a/tools/regz/src/Database.zig +++ b/tools/regz/src/Database.zig @@ -14,29 +14,41 @@ const Allocator = std.mem.Allocator; const Self = @This(); -const Range = struct { - begin: u32, - end: u32, -}; +const PeripheralIndex = u32; +const ClusterIndex = u32; +const RegisterIndex = u32; +const FieldIndex = u32; +const EnumIndex = u32; + +fn IndexRange(comptime Index: type) type { + return struct { + begin: Index, + end: Index, + + fn contains(self: @This(), index: Index) bool { + return index >= self.begin and index < self.end; + } + }; +} const PeripheralUsesInterrupt = struct { - peripheral_idx: u32, + peripheral_idx: PeripheralIndex, interrupt_value: u32, }; const FieldsInRegister = struct { - register_idx: u32, - field_range: Range, + register_idx: RegisterIndex, + field_range: IndexRange(FieldIndex), }; const ClusterInPeripheral = struct { - peripheral_idx: u32, - cluster_idx: u32, + peripheral_idx: PeripheralIndex, + cluster_idx: ClusterIndex, }; const ClusterInCluster = struct { - parent_idx: u32, - child_idx: u32, + parent_idx: ClusterIndex, + child_idx: ClusterIndex, }; const Nesting = enum { @@ -44,6 +56,29 @@ const Nesting = enum { contained, }; +fn RegisterProperties(comptime IndexType: type) type { + return struct { + /// register size in bits + size: std.AutoHashMapUnmanaged(IndexType, usize) = .{}, + + fn deinit(self: *@This(), allocator: Allocator) void { + self.size.deinit(allocator); + } + }; +} + +const RegisterPropertyTables = struct { + register: RegisterProperties(RegisterIndex) = .{}, + cluster: RegisterProperties(ClusterIndex) = .{}, + peripheral: RegisterProperties(PeripheralIndex) = .{}, + + fn deinit(self: *RegisterPropertyTables, allocator: Allocator) void { + self.register.deinit(allocator); + self.cluster.deinit(allocator); + self.peripheral.deinit(allocator); + } +}; + allocator: Allocator, arena: ArenaAllocator, device: ?svd.Device, @@ -57,11 +92,12 @@ enumerations: std.ArrayList(Enumeration), peripherals_use_interrupts: std.ArrayList(PeripheralUsesInterrupt), clusters_in_peripherals: std.ArrayList(ClusterInPeripheral), clusters_in_clusters: std.ArrayList(ClusterInCluster), -registers_in_peripherals: std.AutoHashMap(u32, Range), -registers_in_clusters: std.AutoHashMap(u32, Range), -fields_in_registers: std.AutoHashMap(u32, Range), -enumerations_in_fields: std.AutoHashMap(u32, Range), +registers_in_peripherals: std.AutoHashMap(PeripheralIndex, IndexRange(RegisterIndex)), +registers_in_clusters: std.AutoHashMap(ClusterIndex, IndexRange(RegisterIndex)), +fields_in_registers: std.AutoHashMap(RegisterIndex, IndexRange(FieldIndex)), +enumerations_in_fields: std.AutoHashMap(FieldIndex, IndexRange(EnumIndex)), dimensions: Dimensions, +register_properties: RegisterPropertyTables = .{}, /// takes ownership of arena allocator fn init(allocator: Allocator) Self { @@ -79,10 +115,10 @@ fn init(allocator: Allocator) Self { .peripherals_use_interrupts = std.ArrayList(PeripheralUsesInterrupt).init(allocator), .clusters_in_peripherals = std.ArrayList(ClusterInPeripheral).init(allocator), .clusters_in_clusters = std.ArrayList(ClusterInCluster).init(allocator), - .registers_in_peripherals = std.AutoHashMap(u32, Range).init(allocator), - .registers_in_clusters = std.AutoHashMap(u32, Range).init(allocator), - .fields_in_registers = std.AutoHashMap(u32, Range).init(allocator), - .enumerations_in_fields = std.AutoHashMap(u32, Range).init(allocator), + .registers_in_peripherals = std.AutoHashMap(PeripheralIndex, IndexRange(RegisterIndex)).init(allocator), + .registers_in_clusters = std.AutoHashMap(ClusterIndex, IndexRange(RegisterIndex)).init(allocator), + .fields_in_registers = std.AutoHashMap(RegisterIndex, IndexRange(FieldIndex)).init(allocator), + .enumerations_in_fields = std.AutoHashMap(FieldIndex, IndexRange(EnumIndex)).init(allocator), .dimensions = Dimensions.init(allocator), }; } @@ -102,6 +138,7 @@ pub fn deinit(self: *Self) void { self.registers_in_clusters.deinit(); self.enumerations_in_fields.deinit(); self.dimensions.deinit(); + self.register_properties.deinit(self.allocator); self.arena.deinit(); } @@ -129,13 +166,17 @@ pub fn initFromSvd(allocator: Allocator, doc: *xml.Doc) !Self { const peripheral = try svd.parsePeripheral(&db.arena, peripheral_nodes); try db.peripherals.append(peripheral); - const peripheral_idx = @intCast(u32, db.peripherals.items.len - 1); + const peripheral_idx = @intCast(PeripheralIndex, db.peripherals.items.len - 1); if (xml.getAttribute(peripheral_it, "derivedFrom")) |derived_from| try named_derivations.peripherals.put(peripheral_idx, try db.arena.allocator().dupe(u8, derived_from)); if (try svd.Dimension.parse(&db.arena, peripheral_nodes)) |dimension| try db.dimensions.peripherals.put(peripheral_idx, dimension); + const register_properties = try svd.RegisterProperties.parse(&db.arena, peripheral_nodes); + if (register_properties.size) |size| + try db.register_properties.peripheral.size.put(db.allocator, peripheral_idx, size); + var interrupt_it: ?*xml.Node = xml.findNode(peripheral_nodes, "interrupt"); while (interrupt_it != null) : (interrupt_it = xml.findNode(interrupt_it.?.next, "interrupt")) { const interrupt_nodes: *xml.Node = interrupt_it.?.children orelse continue; @@ -157,8 +198,8 @@ pub fn initFromSvd(allocator: Allocator, doc: *xml.Doc) !Self { const reg_begin_idx = db.registers.items.len; try db.loadRegisters(registers_node.children, &named_derivations); try db.registers_in_peripherals.put(peripheral_idx, .{ - .begin = @intCast(u32, reg_begin_idx), - .end = @intCast(u32, db.registers.items.len), + .begin = @intCast(RegisterIndex, reg_begin_idx), + .end = @intCast(RegisterIndex, db.registers.items.len), }); // process clusters, this might need to be recursive @@ -168,13 +209,18 @@ pub fn initFromSvd(allocator: Allocator, doc: *xml.Doc) !Self { const cluster = try svd.Cluster.parse(&db.arena, cluster_nodes); try db.clusters.append(cluster); - const cluster_idx = @intCast(u32, db.clusters.items.len - 1); + const cluster_idx = @intCast(ClusterIndex, db.clusters.items.len - 1); if (xml.getAttribute(cluster_it, "derivedFrom")) |derived_from| try named_derivations.clusters.put(cluster_idx, try db.arena.allocator().dupe(u8, derived_from)); if (try svd.Dimension.parse(&db.arena, cluster_nodes)) |dimension| try db.dimensions.clusters.put(cluster_idx, dimension); + // TODO: rest of the fields + const cluster_register_props = try svd.RegisterProperties.parse(&db.arena, cluster_nodes); + if (cluster_register_props.size) |size| + try db.register_properties.cluster.size.put(db.allocator, cluster_idx, size); + try db.clusters_in_peripherals.append(.{ .cluster_idx = cluster_idx, .peripheral_idx = peripheral_idx, @@ -183,8 +229,8 @@ pub fn initFromSvd(allocator: Allocator, doc: *xml.Doc) !Self { const first_reg_idx = db.registers.items.len; try db.loadRegisters(cluster_nodes, &named_derivations); try db.registers_in_clusters.put(cluster_idx, .{ - .begin = @intCast(u32, first_reg_idx), - .end = @intCast(u32, db.registers.items.len), + .begin = @intCast(RegisterIndex, first_reg_idx), + .end = @intCast(RegisterIndex, db.registers.items.len), }); try db.loadNestedClusters(cluster_nodes, &named_derivations); @@ -210,7 +256,7 @@ pub fn initFromSvd(allocator: Allocator, doc: *xml.Doc) !Self { var it = named_derivations.peripherals.iterator(); while (it.next()) |entry| { const base_name = entry.value_ptr.*; - const idx = @intCast(u32, for (db.peripherals.items) |peripheral, i| { + const idx = @intCast(PeripheralIndex, for (db.peripherals.items) |peripheral, i| { if (std.mem.eql(u8, base_name, peripheral.name)) break i; } else return error.DerivationNotFound); @@ -220,7 +266,7 @@ pub fn initFromSvd(allocator: Allocator, doc: *xml.Doc) !Self { it = named_derivations.registers.iterator(); while (it.next()) |entry| { const base_name = entry.value_ptr.*; - const idx = @intCast(u32, for (db.registers.items) |register, i| { + const idx = @intCast(RegisterIndex, for (db.registers.items) |register, i| { if (std.mem.eql(u8, base_name, register.name)) break i; } else return error.DerivationNotFound); @@ -280,8 +326,8 @@ fn loadRegisters( var register_it: ?*xml.Node = xml.findNode(nodes, "register"); while (register_it != null) : (register_it = xml.findNode(register_it.?.next, "register")) { const register_nodes: *xml.Node = register_it.?.children orelse continue; - const register = try svd.parseRegister(&db.arena, register_nodes, db.device.?.register_properties.size orelse db.device.?.width); - const register_idx = @intCast(u32, db.registers.items.len); + const register = try svd.parseRegister(&db.arena, register_nodes); + const register_idx = @intCast(RegisterIndex, db.registers.items.len); try db.registers.append(register); if (xml.getAttribute(register_it, "derivedFrom")) |derived_from| @@ -290,7 +336,11 @@ fn loadRegisters( if (try svd.Dimension.parse(&db.arena, register_nodes)) |dimension| try db.dimensions.registers.put(register_idx, dimension); - const field_begin_idx = @intCast(u32, db.fields.items.len); + const register_properties = try svd.RegisterProperties.parse(&db.arena, register_nodes); + if (register_properties.size) |size| + try db.register_properties.register.size.put(db.allocator, register_idx, size); + + const field_begin_idx = @intCast(FieldIndex, db.fields.items.len); if (xml.findNode(register_nodes, "fields")) |fields_node| { var field_it: ?*xml.Node = xml.findNode(fields_node.children, "field"); while (field_it != null) : (field_it = xml.findNode(field_it.?.next, "field")) { @@ -302,7 +352,7 @@ fn loadRegisters( const field = try svd.parseField(&db.arena, field_nodes); try db.fields.append(field); - const field_idx = @intCast(u32, db.fields.items.len - 1); + const field_idx = @intCast(FieldIndex, db.fields.items.len - 1); if (xml.getAttribute(field_it, "derivedFrom")) |derived_from| try named_derivations.fields.put(field_idx, try db.arena.allocator().dupe(u8, derived_from)); @@ -328,7 +378,6 @@ fn loadRegisters( // sort fields by offset std.sort.sort(Field, db.fields.items[field_begin_idx..], {}, Field.lessThan); - // TODO: can we use unions for overlapping fields? // remove overlapping fields var i = field_begin_idx; var current_bit: usize = 0; @@ -362,7 +411,7 @@ fn loadRegisters( if (field_begin_idx != db.fields.items.len) try db.fields_in_registers.put(register_idx, .{ .begin = field_begin_idx, - .end = @intCast(u32, db.fields.items.len), + .end = @intCast(FieldIndex, db.fields.items.len), }); } } @@ -373,7 +422,7 @@ fn loadNestedClusters( nodes: ?*xml.Node, named_derivations: *Derivations([]const u8), ) anyerror!void { - const parent_idx = @intCast(u32, db.clusters.items.len - 1); + const parent_idx = @intCast(ClusterIndex, db.clusters.items.len - 1); var cluster_it: ?*xml.Node = xml.findNode(nodes, "cluster"); while (cluster_it != null) : (cluster_it = xml.findNode(cluster_it.?.next, "cluster")) { @@ -381,13 +430,17 @@ fn loadNestedClusters( const cluster = try svd.Cluster.parse(&db.arena, cluster_nodes); try db.clusters.append(cluster); - const cluster_idx = @intCast(u32, db.clusters.items.len - 1); + const cluster_idx = @intCast(ClusterIndex, db.clusters.items.len - 1); if (xml.getAttribute(cluster_it, "derivedFrom")) |derived_from| try named_derivations.clusters.put(cluster_idx, try db.arena.allocator().dupe(u8, derived_from)); if (try svd.Dimension.parse(&db.arena, cluster_nodes)) |dimension| try db.dimensions.clusters.put(cluster_idx, dimension); + const register_properties = try svd.RegisterProperties.parse(&db.arena, cluster_nodes); + if (register_properties.size) |size| + try db.register_properties.cluster.size.put(db.allocator, cluster_idx, size); + try db.clusters_in_clusters.append(.{ .parent_idx = parent_idx, .child_idx = cluster_idx, @@ -396,8 +449,8 @@ fn loadNestedClusters( const first_reg_idx = db.registers.items.len; try db.loadRegisters(cluster_nodes, named_derivations); try db.registers_in_clusters.put(cluster_idx, .{ - .begin = @intCast(u32, first_reg_idx), - .end = @intCast(u32, db.registers.items.len), + .begin = @intCast(RegisterIndex, first_reg_idx), + .end = @intCast(RegisterIndex, db.registers.items.len), }); try db.loadNestedClusters(cluster_nodes, named_derivations); @@ -541,7 +594,7 @@ pub fn initFromAtdf(allocator: Allocator, doc: *xml.Doc) !Self { while (module_it != null) : (module_it = xml.findNode(module_it.?.next, "module")) { const module_nodes: *xml.Node = module_it.?.children orelse continue; - var value_groups = std.StringHashMap(Range).init(allocator); + var value_groups = std.StringHashMap(IndexRange(u32)).init(allocator); defer value_groups.deinit(); var value_group_it: ?*xml.Node = xml.findNode(module_nodes, "value-group"); @@ -552,7 +605,7 @@ pub fn initFromAtdf(allocator: Allocator, doc: *xml.Doc) !Self { else continue; - const first_enum_idx = @intCast(u32, db.enumerations.items.len); + const first_enum_idx = @intCast(EnumIndex, db.enumerations.items.len); var value_it: ?*xml.Node = xml.findNode(value_group_nodes, "value"); while (value_it != null) : (value_it = xml.findNode(value_it.?.next, "value")) { try db.enumerations.append(.{ @@ -570,7 +623,7 @@ pub fn initFromAtdf(allocator: Allocator, doc: *xml.Doc) !Self { std.sort.sort(Enumeration, db.enumerations.items[first_enum_idx..], {}, Enumeration.lessThan); try value_groups.put(value_group_name, .{ .begin = first_enum_idx, - .end = @intCast(u32, db.enumerations.items.len), + .end = @intCast(EnumIndex, db.enumerations.items.len), }); } @@ -581,17 +634,17 @@ pub fn initFromAtdf(allocator: Allocator, doc: *xml.Doc) !Self { if (!peripheral_instances.contains(group_name)) continue; - const peripheral_idx = @intCast(u32, db.peripherals.items.len); + const peripheral_idx = @intCast(PeripheralIndex, db.peripherals.items.len); try db.peripherals.append(try atdf.parsePeripheral(&db.arena, register_group_it.?)); - const reg_begin_idx = @intCast(u32, db.registers.items.len); + 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_idx = @intCast(u32, db.registers.items.len); + const register_idx = @intCast(RegisterIndex, db.registers.items.len); try db.registers.append(try atdf.parseRegister(&db.arena, register_it.?, regs_start_addr, register_it.?.children != null)); const register_nodes: *xml.Node = register_it.?.children orelse continue; - const field_begin_idx = @intCast(u32, db.fields.items.len); + const field_begin_idx = @intCast(FieldIndex, db.fields.items.len); var bitfield_it: ?*xml.Node = xml.findNode(register_nodes, "bitfield"); while (bitfield_it != null) : (bitfield_it = xml.findNode(bitfield_it.?.next, "bitfield")) { try db.fields.append(atdf.parseField(&db.arena, bitfield_it.?) catch |err| switch (err) { @@ -610,7 +663,7 @@ pub fn initFromAtdf(allocator: Allocator, doc: *xml.Doc) !Self { const field_name = xml.getAttribute(bitfield_it, "name") orelse continue; const field_idx = for (db.fields.items[field_begin_idx..]) |field, offset| { if (std.mem.eql(u8, field_name, field.name)) - break field_begin_idx + @intCast(u32, offset); + break field_begin_idx + @intCast(FieldIndex, offset); } else continue; if (value_groups.get(value_group_name)) |enum_range| @@ -620,13 +673,13 @@ pub fn initFromAtdf(allocator: Allocator, doc: *xml.Doc) !Self { try db.fields_in_registers.put(register_idx, .{ .begin = field_begin_idx, - .end = @intCast(u32, db.fields.items.len), + .end = @intCast(FieldIndex, db.fields.items.len), }); } try db.registers_in_peripherals.put(peripheral_idx, .{ .begin = reg_begin_idx, - .end = @intCast(u32, db.registers.items.len), + .end = @intCast(RegisterIndex, db.registers.items.len), }); } } @@ -803,8 +856,9 @@ pub fn toZig(self: *Self, out_writer: anytype) !void { try writer.print(" pub const version = \"{s}\";\n", .{version}); for (registers) |_, range_offset| { - const reg_idx = @intCast(u32, reg_range.begin + range_offset); - try self.genZigRegister(writer, peripheral.base_addr, reg_idx, .namespaced); + const reg_idx = @intCast(RegisterIndex, reg_range.begin + range_offset); + const register = try self.getRegister(reg_idx); + try self.genZigRegister(writer, peripheral.base_addr, reg_idx, register, .namespaced); } if (has_clusters) { @@ -845,7 +899,7 @@ fn genZigCluster( db: *Self, writer: anytype, base_addr: ?usize, - cluster_idx: u32, + cluster_idx: ClusterIndex, nesting: Nesting, ) !void { const cluster = db.clusters.items[cluster_idx]; @@ -873,10 +927,11 @@ fn genZigCluster( // TODO: check address offset of register wrt the cluster var bits: usize = 0; - for (registers) |register, offset| { - const reg_idx = @intCast(u32, range.begin + offset); - try db.genZigRegister(writer, base_addr, reg_idx, .contained); - bits += register.size; + for (registers) |_, offset| { + const reg_idx = @intCast(RegisterIndex, range.begin + offset); + const register = try db.getRegister(reg_idx); + try db.genZigRegister(writer, base_addr, reg_idx, register, .contained); + bits += register.size.?; } if (bits % 8 != 0 or db.device.?.width % 8 != 0) @@ -897,8 +952,9 @@ fn genZigCluster( } else { try writer.print("pub const {s} = struct {{\n", .{std.zig.fmtId(cluster.name)}); for (registers) |_, offset| { - const reg_idx = @intCast(u32, range.begin + offset); - try db.genZigRegister(writer, base_addr, reg_idx, .namespaced); + const reg_idx = @intCast(RegisterIndex, range.begin + offset); + const register = try db.getRegister(reg_idx); + try db.genZigRegister(writer, base_addr, reg_idx, register, .namespaced); } try writer.writeAll("};\n"); @@ -915,7 +971,7 @@ fn genZigSingleRegister( width: usize, has_base_addr: bool, addr_offset: usize, - field_range_opt: ?Range, + field_range_opt: ?IndexRange(FieldIndex), array_prefix: []const u8, nesting: Nesting, ) !void { @@ -1033,12 +1089,12 @@ fn genZigFields( writer: anytype, reg_width: usize, fields: []Field, - first_field_idx: u32, + first_field_idx: FieldIndex, ) !void { var expected_bit: usize = 0; var reserved_num: usize = 0; for (fields) |field, offset| { - const field_idx = @intCast(u32, first_field_idx + offset); + const field_idx = @intCast(FieldIndex, first_field_idx + offset); const dimension_opt = self.dimensions.fields.get(field_idx); if (dimension_opt) |dimension| { @@ -1138,10 +1194,10 @@ fn genZigRegister( self: *Self, writer: anytype, base_addr: ?usize, - reg_idx: u32, + reg_idx: RegisterIndex, + register: Register, nesting: Nesting, ) !void { - const register = self.registers.items[reg_idx]; const field_range = if (self.fields_in_registers.get(reg_idx)) |range| range else null; const dimension_opt = self.dimensions.registers.get(reg_idx); @@ -1178,7 +1234,7 @@ fn genZigRegister( try self.genZigSingleRegister( writer, name, - register.size, + register.size.?, base_addr != null, addr_offset, field_range, @@ -1212,7 +1268,7 @@ fn genZigRegister( try self.genZigSingleRegister( writer, name, - register.size, + register.size.?, base_addr != null, addr_offset, field_range, @@ -1229,7 +1285,7 @@ fn genZigRegister( } const array_prefix: []const u8 = if (dimension_opt) |dimension| blk: { - if (dimension.increment != register.size / 8) { + if (dimension.increment != register.size.? / 8) { std.log.err("register: {s}", .{register.name}); std.log.err("size: {}", .{register.size}); std.log.err("dimension: {}", .{dimension}); @@ -1267,7 +1323,7 @@ fn genZigRegister( try self.genZigSingleRegister( writer, name, - register.size, + register.size.?, base_addr != null, register.addr_offset, field_range, @@ -1293,21 +1349,97 @@ pub fn toJson(writer: anytype) !void { return error.Todo; } +// TODO: might have to make the index type a param +fn findIndexOfContainer(self: Self, comptime map_field: []const u8, contained_idx: u32) ?u32 { + var iterator = @field(self, map_field).iterator(); + return while (iterator.next()) |entry| { + if (entry.value_ptr.contains(contained_idx)) + break entry.key_ptr.*; + } else null; +} + +fn findClusterContainingRegister(self: Self, reg_idx: RegisterIndex) ?ClusterIndex { + return self.findIndexOfContainer("registers_in_clusters", reg_idx); +} + +fn findClusterContainingCluster(self: Self, cluster_idx: ClusterIndex) ?ClusterIndex { + return for (self.clusters_in_clusters.items) |cic| { + if (cic.child_idx == cluster_idx) + break cic.parent_idx; + } else null; +} + +fn findPeripheralContainingRegister(self: Self, reg_idx: RegisterIndex) ?PeripheralIndex { + return self.findIndexOfContainer("registers_in_peripherals", reg_idx); +} + +fn findPeripheralContainingCluster(self: Self, cluster_idx: ClusterIndex) ?PeripheralIndex { + return for (self.clusters_in_peripherals.items) |cip| { + if (cip.cluster_idx == cluster_idx) + break cip.peripheral_idx; + } else null; +} + +// TODO: get register properties from cluster +pub fn getRegister( + self: Self, + reg_idx: RegisterIndex, +) !Register { + const register = self.registers.items[reg_idx]; + + // build full "path" to register + // first check if + var clusters = std.ArrayListUnmanaged(ClusterIndex){}; + defer clusters.deinit(self.allocator); + + while (true) { + const cluster_idx = if (clusters.items.len == 0) + self.findClusterContainingRegister(reg_idx) orelse break + else + self.findClusterContainingCluster(clusters.items[clusters.items.len - 1]) orelse break; + + try clusters.append(self.allocator, cluster_idx); + } + + const peripheral_idx = if (clusters.items.len == 0) + self.findPeripheralContainingRegister(reg_idx) orelse + return error.PeripheralNotFound + else + self.findPeripheralContainingCluster(clusters.items[clusters.items.len - 1]) orelse + return error.PeripheralNotFound; + + // TODO do upwards search of register, cluster(s), peripheral, and device + const size = self.register_properties.register.size.get(reg_idx) orelse + for (clusters.items) |cluster_idx| + { + if (self.register_properties.cluster.size.get(cluster_idx)) |size| + break size; + } else self.register_properties.peripheral.size.get(peripheral_idx) orelse + self.device.?.register_properties.size orelse return error.SizeNotFound; + + return Register{ + .name = register.name, + .description = register.description, + .addr_offset = register.addr_offset, + .size = size, + }; +} + fn Derivations(comptime T: type) type { return struct { - enumerations: std.AutoHashMap(u32, T), - fields: std.AutoHashMap(u32, T), - registers: std.AutoHashMap(u32, T), - clusters: std.AutoHashMap(u32, T), - peripherals: std.AutoHashMap(u32, T), + enumerations: std.AutoHashMap(EnumIndex, T), + fields: std.AutoHashMap(FieldIndex, T), + registers: std.AutoHashMap(RegisterIndex, T), + clusters: std.AutoHashMap(ClusterIndex, T), + peripherals: std.AutoHashMap(PeripheralIndex, T), fn init(allocator: Allocator) @This() { return @This(){ - .enumerations = std.AutoHashMap(u32, T).init(allocator), - .fields = std.AutoHashMap(u32, T).init(allocator), - .registers = std.AutoHashMap(u32, T).init(allocator), - .clusters = std.AutoHashMap(u32, T).init(allocator), - .peripherals = std.AutoHashMap(u32, T).init(allocator), + .enumerations = std.AutoHashMap(EnumIndex, T).init(allocator), + .fields = std.AutoHashMap(FieldIndex, T).init(allocator), + .registers = std.AutoHashMap(RegisterIndex, T).init(allocator), + .clusters = std.AutoHashMap(ClusterIndex, T).init(allocator), + .peripherals = std.AutoHashMap(PeripheralIndex, T).init(allocator), }; } @@ -1322,17 +1454,17 @@ fn Derivations(comptime T: type) type { } const Dimensions = struct { - fields: std.AutoHashMap(u32, svd.Dimension), - registers: std.AutoHashMap(u32, svd.Dimension), - clusters: std.AutoHashMap(u32, svd.Dimension), - peripherals: std.AutoHashMap(u32, svd.Dimension), + fields: std.AutoHashMap(FieldIndex, svd.Dimension), + registers: std.AutoHashMap(RegisterIndex, svd.Dimension), + clusters: std.AutoHashMap(ClusterIndex, svd.Dimension), + peripherals: std.AutoHashMap(PeripheralIndex, svd.Dimension), fn init(allocator: Allocator) @This() { return @This(){ - .fields = std.AutoHashMap(u32, svd.Dimension).init(allocator), - .registers = std.AutoHashMap(u32, svd.Dimension).init(allocator), - .clusters = std.AutoHashMap(u32, svd.Dimension).init(allocator), - .peripherals = std.AutoHashMap(u32, svd.Dimension).init(allocator), + .fields = std.AutoHashMap(FieldIndex, svd.Dimension).init(allocator), + .registers = std.AutoHashMap(RegisterIndex, svd.Dimension).init(allocator), + .clusters = std.AutoHashMap(ClusterIndex, svd.Dimension).init(allocator), + .peripherals = std.AutoHashMap(PeripheralIndex, svd.Dimension).init(allocator), }; } diff --git a/tools/regz/src/Register.zig b/tools/regz/src/Register.zig index 742335e..df62eaa 100644 --- a/tools/regz/src/Register.zig +++ b/tools/regz/src/Register.zig @@ -1,4 +1,4 @@ name: []const u8, description: ?[]const u8, addr_offset: usize, -size: usize, +size: ?usize, diff --git a/tools/regz/src/svd.zig b/tools/regz/src/svd.zig index b8a442c..0b4e2a1 100644 --- a/tools/regz/src/svd.zig +++ b/tools/regz/src/svd.zig @@ -233,13 +233,13 @@ pub const Interrupt = struct { } }; -pub fn parseRegister(arena: *ArenaAllocator, nodes: *xml.Node, device_width: usize) !Register { +pub fn parseRegister(arena: *ArenaAllocator, nodes: *xml.Node) !Register { const allocator = arena.allocator(); return Register{ .name = try allocator.dupe(u8, xml.findValueForKey(nodes, "name") orelse return error.NoName), .description = try xml.parseDescription(allocator, nodes, "description"), .addr_offset = try std.fmt.parseInt(usize, xml.findValueForKey(nodes, "addressOffset") orelse return error.NoAddrOffset, 0), - .size = (try xml.parseIntForKey(usize, arena.child_allocator, nodes, "size")) orelse device_width, + .size = null, }; } @@ -392,3 +392,14 @@ pub const Dimension = struct { }; } }; + +pub const RegisterProperties = struct { + size: ?usize, + + pub fn parse(arena: *ArenaAllocator, nodes: *xml.Node) !RegisterProperties { + _ = arena; + return RegisterProperties{ + .size = (try xml.parseIntForKey(usize, arena.child_allocator, nodes, "size")), + }; + } +}; diff --git a/tools/regz/tests/svd.zig b/tools/regz/tests/svd.zig index 2bccaf4..3ea7e5e 100644 --- a/tools/regz/tests/svd.zig +++ b/tools/regz/tests/svd.zig @@ -5,14 +5,175 @@ const Database = @import("Database"); const allocator = std.testing.allocator; const expectEqual = std.testing.expectEqual; -test "cmsis example" { - const text = @embedFile("svd/cmsis-example.svd"); +pub fn initDbFromSvd(text: []const u8) !Database { const doc: *xml.Doc = try xml.readFromMemory(text); defer xml.freeDoc(doc); - var db = try Database.initFromSvd(allocator, doc); + return try Database.initFromSvd(allocator, doc); +} + +test "cmsis example" { + var db = try initDbFromSvd(@embedFile("svd/cmsis-example.svd")); defer db.deinit(); // CPU is not populated in this svd file try expectEqual(@as(@TypeOf(db.cpu), null), db.cpu); } + +test "register.size from device" { + var db = try initDbFromSvd( + \\ + \\ ARMCM3xxx + \\ 8 + \\ 32 + \\ 42 + \\ + \\ + \\ TIMER0 + \\ 0x40010000 + \\ + \\ + \\ test + \\ 0x0 + \\ + \\ + \\ + \\ + \\ + \\ + ); + defer db.deinit(); + + const register_idx = 0; + const register = try db.getRegister(register_idx); + + try expectEqual(@as(usize, 42), register.size.?); +} + +test "register.size from peripheral" { + var db = try initDbFromSvd( + \\ + \\ ARMCM3xxx + \\ 8 + \\ 32 + \\ 32 + \\ + \\ + \\ TIMER0 + \\ 0x40010000 + \\ 42 + \\ + \\ + \\ test + \\ 0x0 + \\ + \\ + \\ + \\ + \\ + \\ + ); + defer db.deinit(); + + const register_idx = 0; + const register = try db.getRegister(register_idx); + + try expectEqual(@as(usize, 42), register.size.?); +} + +test "register.size from cluster" { + var db = try initDbFromSvd( + \\ + \\ ARMCM3xxx + \\ 8 + \\ 32 + \\ 32 + \\ + \\ + \\ TIMER0 + \\ 0x40010000 + \\ + \\ + \\ bruh + \\ 42 + \\ 0x0 + \\ + \\ test + \\ 0x0 + \\ + \\ + \\ + \\ + \\ + \\ + \\ + ); + defer db.deinit(); + + const register_idx = 0; + const register = try db.getRegister(register_idx); + + try expectEqual(@as(usize, 42), register.size.?); +} + +// TODO: nested cluster + +test "register.size from register" { + var db = try initDbFromSvd( + \\ + \\ ARMCM3xxx + \\ 8 + \\ 32 + \\ 32 + \\ + \\ + \\ TIMER0 + \\ 0x40010000 + \\ + \\ + \\ test + \\ 0x0 + \\ 42 + \\ + \\ + \\ + \\ + \\ + \\ + ); + defer db.deinit(); + + const register_idx = 0; + const register = try db.getRegister(register_idx); + + try expectEqual(@as(usize, 42), register.size.?); +} + +// TODO: the way this is architected we'd see the error in the code generation side of things +//test "register.size missing" { +// try std.testing.expectError(error.SizeNotFound, initDbFromSvd( +// \\ +// \\ ARMCM3xxx +// \\ 8 +// \\ 32 +// \\ +// \\ +// \\ TIMER0 +// \\ 0x40010000 +// \\ +// \\ +// \\ test +// \\ 0x0 +// \\ +// \\ +// \\ +// \\ +// \\ +// \\ +// )); +//} + +//test "register.access" {} +// TODO: figure out if `protection` is interesting/important for us +//test "register.reset_value" {} +//test "register.reset_mask" {}