diff --git a/tools/regz/src/Database.zig b/tools/regz/src/Database.zig index 7586d06..d9b8dad 100644 --- a/tools/regz/src/Database.zig +++ b/tools/regz/src/Database.zig @@ -303,6 +303,8 @@ pub fn createEntity(db: *Database) EntityId { } pub fn destroyEntity(db: *Database, id: EntityId) void { + // note that if something can be a child, you must remove it from the child + // set of its parent switch (db.getEntityType(id) orelse return) { .register => { log.debug("{}: destroying register", .{id}); @@ -318,9 +320,15 @@ pub fn destroyEntity(db: *Database, id: EntityId) void { // TODO: remove fields _ = db.types.registers.swapRemove(id); }, + .peripheral => { + log.debug("{}: destroying peripheral", .{id}); + // TODO: remove children + _ = db.types.peripherals.swapRemove(id); + }, else => {}, } + db.removeChildren(id); db.removeAttrs(id); } @@ -335,6 +343,22 @@ fn removeAttrs(db: *Database, id: EntityId) void { } } +fn removeChildren(db: *Database, id: EntityId) void { + inline for (@typeInfo(TypeOfField(Database, "children")).Struct.fields) |field| { + if (@field(db.children, field.name).fetchSwapRemove(id)) |children_entry| { + var children_set = children_entry.value; + defer children_set.deinit(db.gpa); + + var it = children_set.iterator(); + while (it.next()) |child_entry| { + const child_id = child_entry.key_ptr.*; + // this will get rid of the parent attr + db.destroyEntity(child_id); + } + } + } +} + pub fn createDevice( db: *Database, opts: struct { @@ -781,7 +805,6 @@ pub fn getEntityIdByName( comptime var group = (tok_it.next() orelse unreachable) ++ "s"; comptime var table = (tok_it.next() orelse unreachable) ++ "s"; - log.debug("group: {s}, table: {s}", .{ group, table }); var it = @field(@field(db, group), table).iterator(); return while (it.next()) |entry| { const entry_id = entry.key_ptr.*; diff --git a/tools/regz/src/gen.zig b/tools/regz/src/gen.zig index 43387e2..d838471 100644 --- a/tools/regz/src/gen.zig +++ b/tools/regz/src/gen.zig @@ -252,7 +252,7 @@ fn writePeripheralInstance(db: Database, instance_id: EntityId, offset: u64, out else ""; - try writer.print("pub const {s} = @ptrCast(*volatile {s}{s}, 0x{x});\n", .{ + try writer.print("pub const {s} = @intToPtr(*volatile {s}{s}, 0x{x});\n", .{ std.zig.fmtId(name), array_prefix, type_ref, @@ -918,7 +918,7 @@ test "gen.peripheral instantiation" { \\pub const devices = struct { \\ pub const TEST_DEVICE = struct { \\ pub const peripherals = struct { - \\ pub const TEST0 = @ptrCast(*volatile types.TEST_PERIPHERAL, 0x1000); + \\ pub const TEST0 = @intToPtr(*volatile types.TEST_PERIPHERAL, 0x1000); \\ }; \\ }; \\}; @@ -950,8 +950,8 @@ test "gen.peripherals with a shared type" { \\pub const devices = struct { \\ pub const TEST_DEVICE = struct { \\ pub const peripherals = struct { - \\ pub const TEST0 = @ptrCast(*volatile types.TEST_PERIPHERAL, 0x1000); - \\ pub const TEST1 = @ptrCast(*volatile types.TEST_PERIPHERAL, 0x2000); + \\ pub const TEST0 = @intToPtr(*volatile types.TEST_PERIPHERAL, 0x1000); + \\ pub const TEST1 = @intToPtr(*volatile types.TEST_PERIPHERAL, 0x2000); \\ }; \\ }; \\}; @@ -1158,8 +1158,8 @@ test "gen.namespaced register groups" { \\pub const devices = struct { \\ pub const ATmega328P = struct { \\ pub const peripherals = struct { - \\ pub const PORTB = @ptrCast(*volatile types.PORT.PORTB, 0x23); - \\ pub const PORTC = @ptrCast(*volatile types.PORT.PORTC, 0x26); + \\ pub const PORTB = @intToPtr(*volatile types.PORT.PORTB, 0x23); + \\ pub const PORTC = @intToPtr(*volatile types.PORT.PORTC, 0x26); \\ }; \\ }; \\}; @@ -1198,7 +1198,7 @@ test "gen.peripheral with reserved register" { \\pub const devices = struct { \\ pub const ATmega328P = struct { \\ pub const peripherals = struct { - \\ pub const PORTB = @ptrCast(*volatile types.PORTB, 0x23); + \\ pub const PORTB = @intToPtr(*volatile types.PORTB, 0x23); \\ }; \\ }; \\}; @@ -1229,7 +1229,7 @@ test "gen.peripheral with count" { \\pub const devices = struct { \\ pub const ATmega328P = struct { \\ pub const peripherals = struct { - \\ pub const PORTB = @ptrCast(*volatile [4]types.PORTB, 0x23); + \\ pub const PORTB = @intToPtr(*volatile [4]types.PORTB, 0x23); \\ }; \\ }; \\}; @@ -1260,7 +1260,7 @@ test "gen.peripheral with count, padding required" { \\pub const devices = struct { \\ pub const ATmega328P = struct { \\ pub const peripherals = struct { - \\ pub const PORTB = @ptrCast(*volatile [4]types.PORTB, 0x23); + \\ pub const PORTB = @intToPtr(*volatile [4]types.PORTB, 0x23); \\ }; \\ }; \\}; @@ -1292,7 +1292,7 @@ test "gen.register with count" { \\pub const devices = struct { \\ pub const ATmega328P = struct { \\ pub const peripherals = struct { - \\ pub const PORTB = @ptrCast(*volatile types.PORTB, 0x23); + \\ pub const PORTB = @intToPtr(*volatile types.PORTB, 0x23); \\ }; \\ }; \\}; @@ -1323,7 +1323,7 @@ test "gen.register with count and fields" { \\pub const devices = struct { \\ pub const ATmega328P = struct { \\ pub const peripherals = struct { - \\ pub const PORTB = @ptrCast(*volatile types.PORTB, 0x23); + \\ pub const PORTB = @intToPtr(*volatile types.PORTB, 0x23); \\ }; \\ }; \\}; diff --git a/tools/regz/src/main.zig b/tools/regz/src/main.zig index 88223a6..640d51a 100644 --- a/tools/regz/src/main.zig +++ b/tools/regz/src/main.zig @@ -137,7 +137,10 @@ fn mainImpl() anyerror!void { var buffered = std.io.bufferedWriter(raw_writer); if (res.args.json) - try db.jsonStringify(.{}, buffered.writer()) + try db.jsonStringify( + .{ .whitespace = .{ .indent = .{ .Space = 2 } } }, + buffered.writer(), + ) else try db.toZig(buffered.writer()); diff --git a/tools/regz/src/svd.zig b/tools/regz/src/svd.zig index 32af2f4..8689c97 100644 --- a/tools/regz/src/svd.zig +++ b/tools/regz/src/svd.zig @@ -164,7 +164,13 @@ pub fn loadIntoDb(db: *Database, doc: xml.Doc) !void { const id = derived_entry.key_ptr.*; const derived_name = derived_entry.value_ptr.*; - try deriveEntity(ctx.db.*, id, derived_name); + deriveEntity(ctx, id, derived_name) catch |err| { + log.warn("failed to derive entity {} from {s}: {}", .{ + id, + derived_name, + err, + }); + }; } db.assertValid(); @@ -225,10 +231,43 @@ fn archFromStr(str: []const u8) Database.Arch { .unknown; } -pub fn deriveEntity(db: Database, id: EntityId, derived_name: []const u8) !void { +pub fn deriveEntity(ctx: Context, id: EntityId, derived_name: []const u8) !void { + const db = ctx.db; log.debug("{}: derived from {s}", .{ id, derived_name }); const entity_type = db.getEntityType(id); - log.warn("TODO: implement derivation for {?}", .{entity_type}); + assert(entity_type != null); + switch (entity_type.?) { + .peripheral => { + // TODO: what do we do when we have other fields set? maybe make + // some assertions and then skip if we're not sure + const name = db.attrs.name.get(id); + const base_instance_id = try db.getEntityIdByName("instance.peripheral", derived_name); + const base_id = db.instances.peripherals.get(base_instance_id) orelse return error.PeripheralNotFound; + + if (ctx.derived_entities.contains(base_id)) { + log.warn("TODO: chained peripheral derivation: {?s}", .{name}); + return error.TodoChainedDerivation; + } + + if (try db.instances.peripherals.fetchPut(db.gpa, id, base_id)) |entry| { + const maybe_remove_peripheral_id = entry.value; + var it = db.instances.peripherals.iterator(); + while (it.next()) |instance_entry| { + const used_peripheral_id = instance_entry.value_ptr.*; + + // if there is a match don't delete the entity + if (used_peripheral_id == maybe_remove_peripheral_id) + break; + } else { + // no instance is using this peripheral so we can remove it + db.destroyEntity(maybe_remove_peripheral_id); + } + } + }, + else => { + log.warn("TODO: implement derivation for {?}", .{entity_type}); + }, + } } pub fn loadPeripheral(ctx: *Context, node: xml.Node, device_id: EntityId) !void {