From e47ad978c74e02928b6385515544965ce6ad7043 Mon Sep 17 00:00:00 2001 From: Matt Ihnen Date: Tue, 15 Oct 2024 08:32:49 -0500 Subject: [PATCH 1/4] Add standalone option to generate register files without microzig dependency --- tools/regz/build.zig | 10 ++++++ tools/regz/src/Database.zig | 4 +-- tools/regz/src/gen.zig | 33 ++++++++++------- tools/regz/src/main.zig | 6 +++- tools/regz/src/mmio.zig | 72 +++++++++++++++++++------------------ 5 files changed, 75 insertions(+), 50 deletions(-) diff --git a/tools/regz/build.zig b/tools/regz/build.zig index 7fed509a..d63599b4 100644 --- a/tools/regz/build.zig +++ b/tools/regz/build.zig @@ -20,6 +20,16 @@ pub fn build(b: *Build) !void { .target = target, .optimize = optimize, }); + + const assets = [_]struct { []const u8, []const u8 }{ + .{ "src/mmio.zig", "mmio_file" }, + }; + + for (assets) |asset| { + const path, const name = asset; + regz.root_module.addAnonymousImport(name, .{ .root_source_file = b.path(path) }); + } + regz.linkLibrary(libxml2_dep.artifact("xml2")); b.installArtifact(regz); diff --git a/tools/regz/src/Database.zig b/tools/regz/src/Database.zig index 340bbbc2..ef676513 100644 --- a/tools/regz/src/Database.zig +++ b/tools/regz/src/Database.zig @@ -985,8 +985,8 @@ pub fn format( _ = writer; } -pub fn to_zig(db: Database, out_writer: anytype) !void { - try gen.to_zig(db, out_writer); +pub fn to_zig(db: Database, out_writer: anytype, standalone: bool) !void { + try gen.to_zig(db, out_writer, standalone); } test "all" { diff --git a/tools/regz/src/gen.zig b/tools/regz/src/gen.zig index d03883c8..3f867464 100644 --- a/tools/regz/src/gen.zig +++ b/tools/regz/src/gen.zig @@ -27,17 +27,24 @@ const EntityWithOffset = struct { } }; -pub fn to_zig(db: Database, out_writer: anytype) !void { +pub fn to_zig(db: Database, out_writer: anytype, standalone: bool) !void { var buffer = std.ArrayList(u8).init(db.arena.allocator()); defer buffer.deinit(); const writer = buffer.writer(); - try writer.writeAll( - \\const micro = @import("microzig"); - \\const mmio = micro.mmio; - \\ - ); - try write_devices(db, writer); + + if (standalone) { + const mmio_content = @embedFile("mmio_file"); + try writer.writeAll(mmio_content); + } else { + try writer.writeAll( + \\const micro = @import("microzig"); + \\const mmio = micro.mmio; + \\ + ); + } + + try write_devices(db, writer, standalone); try write_types(db, writer); try writer.writeByte(0); @@ -65,7 +72,7 @@ pub fn to_zig(db: Database, out_writer: anytype) !void { try out_writer.writeAll(text); } -fn write_devices(db: Database, writer: anytype) !void { +fn write_devices(db: Database, writer: anytype, standalone: bool) !void { if (db.instances.devices.count() == 0) return; @@ -77,7 +84,7 @@ fn write_devices(db: Database, writer: anytype) !void { // TODO: order devices alphabetically for (db.instances.devices.keys()) |device_id| { - write_device(db, device_id, writer) catch |err| { + write_device(db, device_id, writer, standalone) catch |err| { log.warn("failed to write device: {}", .{err}); }; } @@ -119,7 +126,7 @@ fn write_string(str: []const u8, writer: anytype) !void { } } -fn write_device(db: Database, device_id: EntityId, out_writer: anytype) !void { +fn write_device(db: Database, device_id: EntityId, out_writer: anytype, standalone: bool) !void { assert(db.entity_is("instance.device", device_id)); const name = db.attrs.name.get(device_id) orelse return error.MissingDeviceName; @@ -153,8 +160,10 @@ fn write_device(db: Database, device_id: EntityId, out_writer: anytype) !void { try writer.writeAll("};\n\n"); } - write_vector_table(db, device_id, writer) catch |err| - log.warn("failed to write vector table: {}", .{err}); + if (!standalone) { + write_vector_table(db, device_id, writer) catch |err| + log.warn("failed to write vector table: {}", .{err}); + } if (db.children.peripherals.get(device_id)) |peripheral_set| { var list = std.ArrayList(EntityWithOffset).init(db.gpa); diff --git a/tools/regz/src/main.zig b/tools/regz/src/main.zig index dae5c211..b9123a1e 100644 --- a/tools/regz/src/main.zig +++ b/tools/regz/src/main.zig @@ -22,6 +22,7 @@ const Arguments = struct { input_path: ?[]const u8 = null, output_path: ?[]const u8 = null, output_json: bool = false, + standalone: bool = false, help: bool = false, fn deinit(args: *Arguments) void { @@ -37,6 +38,7 @@ fn print_usage(writer: anytype) !void { \\ --schema Explicitly set schema type, one of: svd, atdf, json \\ --output_path Write to a file \\ --json Write output as JSON + \\ --standalone Write standalone output with no microzig dependencies \\ \\ ); @@ -73,6 +75,8 @@ fn parse_args(allocator: Allocator) !Arguments { ret.output_path = try allocator.dupe(u8, args[i]); } else if (std.mem.eql(u8, args[i], "--json")) { ret.output_json = true; + } else if (std.mem.eql(u8, args[i], "--standalone")) { + ret.standalone = true; } else if (std.mem.startsWith(u8, args[i], "-")) { std.log.err("Unknown argument '{s}'", .{args[i]}); try print_usage(std.io.getStdErr().writer()); @@ -156,7 +160,7 @@ fn main_impl() anyerror!void { buffered.writer(), ) else - try db.to_zig(buffered.writer()); + try db.to_zig(buffered.writer(), args.standalone); try buffered.flush(); } diff --git a/tools/regz/src/mmio.zig b/tools/regz/src/mmio.zig index e1c86f3b..dcad84d7 100644 --- a/tools/regz/src/mmio.zig +++ b/tools/regz/src/mmio.zig @@ -1,49 +1,51 @@ const std = @import("std"); -pub fn Mmio(comptime size: u8, comptime PackedT: type) type { - if ((size % 8) != 0) - @compileError("size must be divisible by 8!"); +pub const mmio = struct { + pub fn Mmio(comptime size: u8, comptime PackedT: type) type { + if ((size % 8) != 0) + @compileError("size must be divisible by 8!"); - if (!std.math.isPowerOfTwo(size / 8)) - @compileError("size must encode a power of two number of bytes!"); + if (!std.math.isPowerOfTwo(size / 8)) + @compileError("size must encode a power of two number of bytes!"); - const IntT = std.meta.Int(.unsigned, size); + const IntT = std.meta.Int(.unsigned, size); - if (@sizeOf(PackedT) != (size / 8)) - @compileError(std.fmt.comptimePrint("IntT and PackedT must have the same size!, they are {} and {} bytes respectively", .{ size / 8, @sizeOf(PackedT) })); + if (@sizeOf(PackedT) != (size / 8)) + @compileError(std.fmt.comptimePrint("IntT and PackedT must have the same size!, they are {} and {} bytes respectively", .{ size / 8, @sizeOf(PackedT) })); - return extern struct { - const Self = @This(); + return extern struct { + const Self = @This(); - raw: IntT, + raw: IntT, - pub const underlying_type = PackedT; + pub const underlying_type = PackedT; - pub inline fn read(addr: *volatile Self) PackedT { - return @as(PackedT, @bitCast(addr.raw)); - } + pub inline fn read(addr: *volatile Self) PackedT { + return @as(PackedT, @bitCast(addr.raw)); + } - pub inline fn write(addr: *volatile Self, val: PackedT) void { - // This is a workaround for a compiler bug related to miscompilation - // If the tmp var is not used, result location will fuck things up - var tmp = @as(IntT, @bitCast(val)); - addr.raw = tmp; - } + pub inline fn write(addr: *volatile Self, val: PackedT) void { + // This is a workaround for a compiler bug related to miscompilation + // If the tmp var is not used, result location will fuck things up + var tmp = @as(IntT, @bitCast(val)); + addr.raw = tmp; + } - pub inline fn modify(addr: *volatile Self, fields: anytype) void { - var val = read(addr); - inline for (@typeInfo(@TypeOf(fields)).Struct.fields) |field| { - @field(val, field.name) = @field(fields, field.name); + pub inline fn modify(addr: *volatile Self, fields: anytype) void { + var val = read(addr); + inline for (@typeInfo(@TypeOf(fields)).Struct.fields) |field| { + @field(val, field.name) = @field(fields, field.name); + } + write(addr, val); } - write(addr, val); - } - pub inline fn toggle(addr: *volatile Self, fields: anytype) void { - var val = read(addr); - inline for (@typeInfo(@TypeOf(fields)).Struct.fields) |field| { - @field(val, field.name) = @field(val, field.name) ^ @field(fields, field.name); + pub inline fn toggle(addr: *volatile Self, fields: anytype) void { + var val = read(addr); + inline for (@typeInfo(@TypeOf(fields)).Struct.fields) |field| { + @field(val, field.name) = @field(val, field.name) ^ @field(fields, field.name); + } + write(addr, val); } - write(addr, val); - } - }; -} + }; + } +}; From 1c22d72c7d63ab4821f8cec1e8d68f1cd711f092 Mon Sep 17 00:00:00 2001 From: Matt Ihnen Date: Tue, 15 Oct 2024 08:38:22 -0500 Subject: [PATCH 2/4] Update regz's version of Mmio with core/src version --- tools/regz/src/mmio.zig | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/tools/regz/src/mmio.zig b/tools/regz/src/mmio.zig index dcad84d7..3fa4c2aa 100644 --- a/tools/regz/src/mmio.zig +++ b/tools/regz/src/mmio.zig @@ -1,7 +1,9 @@ const std = @import("std"); +const assert = std.debug.assert; pub const mmio = struct { - pub fn Mmio(comptime size: u8, comptime PackedT: type) type { + pub fn Mmio(comptime PackedT: type) type { + const size = @bitSizeOf(PackedT); if ((size % 8) != 0) @compileError("size must be divisible by 8!"); @@ -21,14 +23,18 @@ pub const mmio = struct { pub const underlying_type = PackedT; pub inline fn read(addr: *volatile Self) PackedT { - return @as(PackedT, @bitCast(addr.raw)); + return @bitCast(addr.raw); } pub inline fn write(addr: *volatile Self, val: PackedT) void { - // This is a workaround for a compiler bug related to miscompilation - // If the tmp var is not used, result location will fuck things up - var tmp = @as(IntT, @bitCast(val)); - addr.raw = tmp; + comptime { + assert(@bitSizeOf(PackedT) == @bitSizeOf(IntT)); + } + addr.write_raw(@bitCast(val)); + } + + pub fn write_raw(addr: *volatile Self, val: IntT) void { + addr.raw = val; } pub inline fn modify(addr: *volatile Self, fields: anytype) void { From 5aa3687722ce07ee2eb2a4e7812f3846e6208049 Mon Sep 17 00:00:00 2001 From: Matt Ihnen Date: Tue, 15 Oct 2024 08:49:18 -0500 Subject: [PATCH 3/4] Remove regz's copy of mmio and wrap into struct inside generated file during standalone mode. --- tools/regz/build.zig | 2 +- tools/regz/src/gen.zig | 2 ++ tools/regz/src/mmio.zig | 57 ----------------------------------------- 3 files changed, 3 insertions(+), 58 deletions(-) delete mode 100644 tools/regz/src/mmio.zig diff --git a/tools/regz/build.zig b/tools/regz/build.zig index d63599b4..0c3dd356 100644 --- a/tools/regz/build.zig +++ b/tools/regz/build.zig @@ -22,7 +22,7 @@ pub fn build(b: *Build) !void { }); const assets = [_]struct { []const u8, []const u8 }{ - .{ "src/mmio.zig", "mmio_file" }, + .{ "../../core/src/mmio.zig", "mmio_file" }, }; for (assets) |asset| { diff --git a/tools/regz/src/gen.zig b/tools/regz/src/gen.zig index 3f867464..b436bb72 100644 --- a/tools/regz/src/gen.zig +++ b/tools/regz/src/gen.zig @@ -35,7 +35,9 @@ pub fn to_zig(db: Database, out_writer: anytype, standalone: bool) !void { if (standalone) { const mmio_content = @embedFile("mmio_file"); + try writer.writeAll("pub const mmio = struct {"); try writer.writeAll(mmio_content); + try writer.writeAll("};"); } else { try writer.writeAll( \\const micro = @import("microzig"); diff --git a/tools/regz/src/mmio.zig b/tools/regz/src/mmio.zig deleted file mode 100644 index 3fa4c2aa..00000000 --- a/tools/regz/src/mmio.zig +++ /dev/null @@ -1,57 +0,0 @@ -const std = @import("std"); -const assert = std.debug.assert; - -pub const mmio = struct { - pub fn Mmio(comptime PackedT: type) type { - const size = @bitSizeOf(PackedT); - if ((size % 8) != 0) - @compileError("size must be divisible by 8!"); - - if (!std.math.isPowerOfTwo(size / 8)) - @compileError("size must encode a power of two number of bytes!"); - - const IntT = std.meta.Int(.unsigned, size); - - if (@sizeOf(PackedT) != (size / 8)) - @compileError(std.fmt.comptimePrint("IntT and PackedT must have the same size!, they are {} and {} bytes respectively", .{ size / 8, @sizeOf(PackedT) })); - - return extern struct { - const Self = @This(); - - raw: IntT, - - pub const underlying_type = PackedT; - - pub inline fn read(addr: *volatile Self) PackedT { - return @bitCast(addr.raw); - } - - pub inline fn write(addr: *volatile Self, val: PackedT) void { - comptime { - assert(@bitSizeOf(PackedT) == @bitSizeOf(IntT)); - } - addr.write_raw(@bitCast(val)); - } - - pub fn write_raw(addr: *volatile Self, val: IntT) void { - addr.raw = val; - } - - pub inline fn modify(addr: *volatile Self, fields: anytype) void { - var val = read(addr); - inline for (@typeInfo(@TypeOf(fields)).Struct.fields) |field| { - @field(val, field.name) = @field(fields, field.name); - } - write(addr, val); - } - - pub inline fn toggle(addr: *volatile Self, fields: anytype) void { - var val = read(addr); - inline for (@typeInfo(@TypeOf(fields)).Struct.fields) |field| { - @field(val, field.name) = @field(val, field.name) ^ @field(fields, field.name); - } - write(addr, val); - } - }; - } -}; From 1d0d417e91f7d3baa40f5648a401b792c2e76527 Mon Sep 17 00:00:00 2001 From: Matt Ihnen Date: Tue, 15 Oct 2024 10:41:04 -0500 Subject: [PATCH 4/4] Fix tests --- tools/regz/build.zig | 14 ++++++++++---- tools/regz/src/gen.zig | 34 +++++++++++++++++----------------- 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/tools/regz/build.zig b/tools/regz/build.zig index 0c3dd356..03f75298 100644 --- a/tools/regz/build.zig +++ b/tools/regz/build.zig @@ -14,6 +14,10 @@ pub fn build(b: *Build) !void { .iconv = false, }); + const assets = [_]struct { []const u8, []const u8 }{ + .{ "../../core/src/mmio.zig", "mmio_file" }, + }; + const regz = b.addExecutable(.{ .name = "regz", .root_source_file = b.path("src/main.zig"), @@ -21,10 +25,6 @@ pub fn build(b: *Build) !void { .optimize = optimize, }); - const assets = [_]struct { []const u8, []const u8 }{ - .{ "../../core/src/mmio.zig", "mmio_file" }, - }; - for (assets) |asset| { const path, const name = asset; regz.root_module.addAnonymousImport(name, .{ .root_source_file = b.path(path) }); @@ -75,6 +75,12 @@ pub fn build(b: *Build) !void { .target = target, .optimize = optimize, }); + + for (assets) |asset| { + const path, const name = asset; + tests.root_module.addAnonymousImport(name, .{ .root_source_file = b.path(path) }); + } + tests.linkLibrary(libxml2_dep.artifact("xml2")); const run_tests = b.addRunArtifact(tests); const test_step = b.step("test", "Run unit tests"); diff --git a/tools/regz/src/gen.zig b/tools/regz/src/gen.zig index b436bb72..47c9b24d 100644 --- a/tools/regz/src/gen.zig +++ b/tools/regz/src/gen.zig @@ -902,7 +902,7 @@ test "gen.peripheral type with register and field" { var buffer = std.ArrayList(u8).init(std.testing.allocator); defer buffer.deinit(); - try db.to_zig(buffer.writer()); + try db.to_zig(buffer.writer(), false); try std.testing.expectEqualStrings( \\const micro = @import("microzig"); \\const mmio = micro.mmio; @@ -928,7 +928,7 @@ test "gen.peripheral instantiation" { var buffer = std.ArrayList(u8).init(std.testing.allocator); defer buffer.deinit(); - try db.to_zig(buffer.writer()); + try db.to_zig(buffer.writer(), false); try std.testing.expectEqualStrings( \\const micro = @import("microzig"); \\const mmio = micro.mmio; @@ -962,7 +962,7 @@ test "gen.peripherals with a shared type" { var buffer = std.ArrayList(u8).init(std.testing.allocator); defer buffer.deinit(); - try db.to_zig(buffer.writer()); + try db.to_zig(buffer.writer(), false); try std.testing.expectEqualStrings( \\const micro = @import("microzig"); \\const mmio = micro.mmio; @@ -997,7 +997,7 @@ test "gen.peripheral with modes" { var buffer = std.ArrayList(u8).init(std.testing.allocator); defer buffer.deinit(); - try db.to_zig(buffer.writer()); + try db.to_zig(buffer.writer(), false); try std.testing.expectEqualStrings( \\const micro = @import("microzig"); \\const mmio = micro.mmio; @@ -1059,7 +1059,7 @@ test "gen.peripheral with enum" { var buffer = std.ArrayList(u8).init(std.testing.allocator); defer buffer.deinit(); - try db.to_zig(buffer.writer()); + try db.to_zig(buffer.writer(), false); try std.testing.expectEqualStrings( \\const micro = @import("microzig"); \\const mmio = micro.mmio; @@ -1088,7 +1088,7 @@ test "gen.peripheral with enum, enum is exhausted of values" { var buffer = std.ArrayList(u8).init(std.testing.allocator); defer buffer.deinit(); - try db.to_zig(buffer.writer()); + try db.to_zig(buffer.writer(), false); try std.testing.expectEqualStrings( \\const micro = @import("microzig"); \\const mmio = micro.mmio; @@ -1116,7 +1116,7 @@ test "gen.field with named enum" { var buffer = std.ArrayList(u8).init(std.testing.allocator); defer buffer.deinit(); - try db.to_zig(buffer.writer()); + try db.to_zig(buffer.writer(), false); try std.testing.expectEqualStrings( \\const micro = @import("microzig"); \\const mmio = micro.mmio; @@ -1151,7 +1151,7 @@ test "gen.field with anonymous enum" { var buffer = std.ArrayList(u8).init(std.testing.allocator); defer buffer.deinit(); - try db.to_zig(buffer.writer()); + try db.to_zig(buffer.writer(), false); try std.testing.expectEqualStrings( \\const micro = @import("microzig"); \\const mmio = micro.mmio; @@ -1184,7 +1184,7 @@ test "gen.namespaced register groups" { var buffer = std.ArrayList(u8).init(std.testing.allocator); defer buffer.deinit(); - try db.to_zig(buffer.writer()); + try db.to_zig(buffer.writer(), false); try std.testing.expectEqualStrings( \\const micro = @import("microzig"); \\const mmio = micro.mmio; @@ -1226,7 +1226,7 @@ test "gen.peripheral with reserved register" { var buffer = std.ArrayList(u8).init(std.testing.allocator); defer buffer.deinit(); - try db.to_zig(buffer.writer()); + try db.to_zig(buffer.writer(), false); try std.testing.expectEqualStrings( \\const micro = @import("microzig"); \\const mmio = micro.mmio; @@ -1259,7 +1259,7 @@ test "gen.peripheral with count" { var buffer = std.ArrayList(u8).init(std.testing.allocator); defer buffer.deinit(); - try db.to_zig(buffer.writer()); + try db.to_zig(buffer.writer(), false); try std.testing.expectEqualStrings( \\const micro = @import("microzig"); \\const mmio = micro.mmio; @@ -1292,7 +1292,7 @@ test "gen.peripheral with count, padding required" { var buffer = std.ArrayList(u8).init(std.testing.allocator); defer buffer.deinit(); - try db.to_zig(buffer.writer()); + try db.to_zig(buffer.writer(), false); try std.testing.expectEqualStrings( \\const micro = @import("microzig"); \\const mmio = micro.mmio; @@ -1326,7 +1326,7 @@ test "gen.register with count" { var buffer = std.ArrayList(u8).init(std.testing.allocator); defer buffer.deinit(); - try db.to_zig(buffer.writer()); + try db.to_zig(buffer.writer(), false); try std.testing.expectEqualStrings( \\const micro = @import("microzig"); \\const mmio = micro.mmio; @@ -1359,7 +1359,7 @@ test "gen.register with count and fields" { var buffer = std.ArrayList(u8).init(std.testing.allocator); defer buffer.deinit(); - try db.to_zig(buffer.writer()); + try db.to_zig(buffer.writer(), false); try std.testing.expectEqualStrings( \\const micro = @import("microzig"); \\const mmio = micro.mmio; @@ -1395,7 +1395,7 @@ test "gen.field with count, width of one, offset, and padding" { var buffer = std.ArrayList(u8).init(std.testing.allocator); defer buffer.deinit(); - try db.to_zig(buffer.writer()); + try db.to_zig(buffer.writer(), false); try std.testing.expectEqualStrings( \\const micro = @import("microzig"); \\const mmio = micro.mmio; @@ -1422,7 +1422,7 @@ test "gen.field with count, multi-bit width, offset, and padding" { var buffer = std.ArrayList(u8).init(std.testing.allocator); defer buffer.deinit(); - try db.to_zig(buffer.writer()); + try db.to_zig(buffer.writer(), false); try std.testing.expectEqualStrings( \\const micro = @import("microzig"); \\const mmio = micro.mmio; @@ -1449,7 +1449,7 @@ test "gen.interrupts.avr" { var buffer = std.ArrayList(u8).init(std.testing.allocator); defer buffer.deinit(); - try db.to_zig(buffer.writer()); + try db.to_zig(buffer.writer(), false); try std.testing.expectEqualStrings( \\const micro = @import("microzig"); \\const mmio = micro.mmio;