From f6bd2480d73654c4d5ffa6b60c44f1489bc063b2 Mon Sep 17 00:00:00 2001 From: Matt Knight Date: Sun, 22 Dec 2024 12:40:46 -0800 Subject: [PATCH] Directly generate enums (#328) * directly generate enums * fix rp2xxx usb * implement patching * remove some debug logs * fix esp --- examples/build.zig | 2 +- examples/build.zig.zon | 2 +- examples/nxp/lpc/src/blinky.zig | 8 +- .../rp2xxx/src/hal/clocks/common.zig | 10 +- port/raspberrypi/rp2xxx/src/hal/dma.zig | 12 +- port/raspberrypi/rp2xxx/src/hal/gpio.zig | 60 ++----- port/raspberrypi/rp2xxx/src/hal/i2c.zig | 78 ++++----- port/raspberrypi/rp2xxx/src/hal/random.zig | 12 +- port/raspberrypi/rp2xxx/src/hal/usb.zig | 9 +- tools/regz/src/Database.zig | 151 ++++++++++++++++++ tools/regz/src/gen.zig | 76 +++------ 11 files changed, 256 insertions(+), 164 deletions(-) diff --git a/examples/build.zig b/examples/build.zig index cea00ae3e..5c6efc0c1 100644 --- a/examples/build.zig +++ b/examples/build.zig @@ -1,7 +1,7 @@ const std = @import("std"); const example_dep_names: []const []const u8 = &.{ - //"espressif/esp", + "espressif/esp", "gigadevice/gd32", "microchip/atsam", "microchip/avr", diff --git a/examples/build.zig.zon b/examples/build.zig.zon index 6103e3f34..4b7d0d15c 100644 --- a/examples/build.zig.zon +++ b/examples/build.zig.zon @@ -3,7 +3,7 @@ .version = "0.0.0", .dependencies = .{ // examples - // .@"espressif/esp" = .{ .path = "espressif/esp" }, + .@"espressif/esp" = .{ .path = "espressif/esp" }, .@"gigadevice/gd32" = .{ .path = "gigadevice/gd32" }, .@"microchip/atsam" = .{ .path = "microchip/atsam" }, .@"microchip/avr" = .{ .path = "microchip/avr" }, diff --git a/examples/nxp/lpc/src/blinky.zig b/examples/nxp/lpc/src/blinky.zig index 328d63705..7371dd5c2 100644 --- a/examples/nxp/lpc/src/blinky.zig +++ b/examples/nxp/lpc/src/blinky.zig @@ -21,10 +21,10 @@ const all_mask = led_mask[0] | led_mask[1] | led_mask[2] | led_mask[3]; pub fn main() !void { conn.PINSEL3.modify(.{ - .P1_18 = .{ .value = .GPIO_P1 }, - .P1_20 = .{ .value = .GPIO_P1 }, - .P1_21 = .{ .value = .GPIO_P1 }, - .P1_23 = .{ .value = .GPIO_P1 }, + .P1_18 = .GPIO_P1, + .P1_20 = .GPIO_P1, + .P1_21 = .GPIO_P1, + .P1_23 = .GPIO_P1, }); const p1 = &gpio[1]; diff --git a/port/raspberrypi/rp2xxx/src/hal/clocks/common.zig b/port/raspberrypi/rp2xxx/src/hal/clocks/common.zig index e9776a569..347003d15 100644 --- a/port/raspberrypi/rp2xxx/src/hal/clocks/common.zig +++ b/port/raspberrypi/rp2xxx/src/hal/clocks/common.zig @@ -24,19 +24,19 @@ pub const xosc = struct { } pub fn init() void { if (xosc_freq <= 15_000_000 and xosc_freq >= 1_000_000) { - XOSC.CTRL.modify(.{ .FREQ_RANGE = .{ .value = .@"1_15MHZ" } }); + XOSC.CTRL.modify(.{ .FREQ_RANGE = .@"1_15MHZ" }); } else if (xosc_freq <= 30_000_000 and xosc_freq >= 10_000_000) { - XOSC.CTRL.modify(.{ .FREQ_RANGE = .{ .value = .@"10_30MHZ" } }); + XOSC.CTRL.modify(.{ .FREQ_RANGE = .@"10_30MHZ" }); } else if (xosc_freq <= 60_000_000 and xosc_freq >= 25_000_000) { - XOSC.CTRL.modify(.{ .FREQ_RANGE = .{ .value = .@"25_60MHZ" } }); + XOSC.CTRL.modify(.{ .FREQ_RANGE = .@"25_60MHZ" }); } else if (xosc_freq <= 100_000_000 and xosc_freq >= 40_000_000) { - XOSC.CTRL.modify(.{ .FREQ_RANGE = .{ .value = .@"40_100MHZ" } }); + XOSC.CTRL.modify(.{ .FREQ_RANGE = .@"40_100MHZ" }); } else { unreachable; } XOSC.STARTUP.modify(.{ .DELAY = startup_delay_value }); - XOSC.CTRL.modify(.{ .ENABLE = .{ .value = .ENABLE } }); + XOSC.CTRL.modify(.{ .ENABLE = .ENABLE }); // wait for xosc startup to complete: while (XOSC.STATUS.read().STABLE == 0) {} diff --git a/port/raspberrypi/rp2xxx/src/hal/dma.zig b/port/raspberrypi/rp2xxx/src/hal/dma.zig index b7f962940..11d77d518 100644 --- a/port/raspberrypi/rp2xxx/src/hal/dma.zig +++ b/port/raspberrypi/rp2xxx/src/hal/dma.zig @@ -106,13 +106,11 @@ pub const Channel = enum(u4) { regs.trans_count = count; regs.ctrl_trig.modify(.{ .EN = @intFromBool(config.enable), - .DATA_SIZE = .{ - .value = switch (config.transfer_size_bytes) { - 1 => @TypeOf(regs.ctrl_trig.read().DATA_SIZE.value).SIZE_BYTE, - 2 => .SIZE_HALFWORD, - 4 => .SIZE_WORD, - else => unreachable, - }, + .DATA_SIZE = switch (config.transfer_size_bytes) { + 1 => @TypeOf(regs.ctrl_trig.read().DATA_SIZE.value).SIZE_BYTE, + 2 => .SIZE_HALFWORD, + 4 => .SIZE_WORD, + else => unreachable, }, .INCR_READ = @intFromBool(config.read_increment), .INCR_WRITE = @intFromBool(config.write_increment), diff --git a/port/raspberrypi/rp2xxx/src/hal/gpio.zig b/port/raspberrypi/rp2xxx/src/hal/gpio.zig index b49711316..4927dbfcd 100644 --- a/port/raspberrypi/rp2xxx/src/hal/gpio.zig +++ b/port/raspberrypi/rp2xxx/src/hal/gpio.zig @@ -264,58 +264,28 @@ pub const Pin = enum(u6) { .RP2040 => extern struct { status: @TypeOf(IO_BANK0.GPIO0_STATUS), ctrl: microzig.mmio.Mmio(packed struct(u32) { - FUNCSEL: packed union { - raw: u5, - value: Function, - }, + FUNCSEL: Function, reserved8: u3, - OUTOVER: packed union { - raw: u2, - value: Override, - }, + OUTOVER: Override, reserved12: u2, - OEOVER: packed union { - raw: u2, - value: Override, - }, + OEOVER: Override, reserved16: u2, - INOVER: packed union { - raw: u2, - value: Override, - }, + INOVER: Override, reserved28: u10, - IRQOVER: packed union { - raw: u2, - value: Override, - }, + IRQOVER: Override, padding: u2, }), }, .RP2350 => extern struct { status: @TypeOf(IO_BANK0.GPIO0_STATUS), ctrl: microzig.mmio.Mmio(packed struct(u32) { - FUNCSEL: packed union { - raw: u5, - value: Function, - }, + FUNCSEL: Function, reserved12: u7, - OUTOVER: packed union { - raw: u2, - value: Override, - }, - OEOVER: packed union { - raw: u2, - value: Override, - }, - INOVER: packed union { - raw: u2, - value: Override, - }, + OUTOVER: Override, + OEOVER: Override, + INOVER: Override, reserved28: u10, - IRQOVER: packed union { - raw: u2, - value: Override, - }, + IRQOVER: Override, padding: u2, }), }, @@ -471,11 +441,11 @@ pub const Pin = enum(u6) { const regs = gpio.get_regs(); regs.ctrl.modify(.{ - .FUNCSEL = .{ .value = function }, - .OUTOVER = .{ .value = .normal }, - .INOVER = .{ .value = .normal }, - .IRQOVER = .{ .value = .normal }, - .OEOVER = .{ .value = .normal }, + .FUNCSEL = function, + .OUTOVER = .normal, + .INOVER = .normal, + .IRQOVER = .normal, + .OEOVER = .normal, }); switch (cpu) { diff --git a/port/raspberrypi/rp2xxx/src/hal/i2c.zig b/port/raspberrypi/rp2xxx/src/hal/i2c.zig index ddc09b050..e67d22401 100644 --- a/port/raspberrypi/rp2xxx/src/hal/i2c.zig +++ b/port/raspberrypi/rp2xxx/src/hal/i2c.zig @@ -217,18 +217,18 @@ pub const I2C = enum(u1) { inline fn disable(i2c: I2C) void { i2c.get_regs().IC_ENABLE.write(.{ - .ENABLE = .{ .value = .DISABLED }, - .ABORT = .{ .value = .DISABLE }, - .TX_CMD_BLOCK = .{ .value = .NOT_BLOCKED }, + .ENABLE = .DISABLED, + .ABORT = .DISABLE, + .TX_CMD_BLOCK = .NOT_BLOCKED, .padding = 0, }); } inline fn enable(i2c: I2C) void { i2c.get_regs().IC_ENABLE.write(.{ - .ENABLE = .{ .value = .ENABLED }, - .ABORT = .{ .value = .DISABLE }, - .TX_CMD_BLOCK = .{ .value = .NOT_BLOCKED }, + .ENABLE = .ENABLED, + .ABORT = .DISABLE, + .TX_CMD_BLOCK = .NOT_BLOCKED, .padding = 0, }); } @@ -244,15 +244,15 @@ pub const I2C = enum(u1) { i2c.disable(); const regs = i2c.get_regs(); regs.IC_CON.write(.{ - .MASTER_MODE = .{ .value = .ENABLED }, - .SPEED = .{ .value = .FAST }, - .IC_RESTART_EN = .{ .value = if (config.repeated_start) .ENABLED else .DISABLED }, - .IC_SLAVE_DISABLE = .{ .value = .SLAVE_DISABLED }, - .TX_EMPTY_CTRL = .{ .value = .ENABLED }, - .IC_10BITADDR_SLAVE = .{ .raw = 0 }, - .IC_10BITADDR_MASTER = .{ .raw = 0 }, - .STOP_DET_IFADDRESSED = .{ .raw = 0 }, - .RX_FIFO_FULL_HLD_CTRL = .{ .raw = 0 }, + .MASTER_MODE = .ENABLED, + .SPEED = .FAST, + .IC_RESTART_EN = if (config.repeated_start) .ENABLED else .DISABLED, + .IC_SLAVE_DISABLE = .SLAVE_DISABLED, + .TX_EMPTY_CTRL = .ENABLED, + .IC_10BITADDR_SLAVE = @enumFromInt(0), + .IC_10BITADDR_MASTER = @enumFromInt(0), + .STOP_DET_IFADDRESSED = @enumFromInt(0), + .RX_FIFO_FULL_HLD_CTRL = @enumFromInt(0), .STOP_DET_IF_MASTER_ACTIVE = 0, .padding = 0, }); @@ -263,8 +263,8 @@ pub const I2C = enum(u1) { // DREQ signal control regs.IC_DMA_CR.write(.{ - .RDMAE = .{ .value = .ENABLED }, - .TDMAE = .{ .value = .ENABLED }, + .RDMAE = .ENABLED, + .TDMAE = .ENABLED, .padding = 0, }); @@ -308,8 +308,8 @@ pub const I2C = enum(u1) { i2c.disable(); i2c.get_regs().IC_TAR.write(.{ .IC_TAR = @intFromEnum(addr), - .GC_OR_START = .{ .value = .GENERAL_CALL }, - .SPECIAL = .{ .value = .DISABLED }, + .GC_OR_START = .GENERAL_CALL, + .SPECIAL = .DISABLED, .padding = 0, }); i2c.enable(); @@ -324,10 +324,10 @@ pub const I2C = enum(u1) { // IC_CLR_TX_ABRT register always reads as 0. _ = regs.IC_CLR_TX_ABRT.read(); - if (abort_reason.ABRT_7B_ADDR_NOACK.value == .ACTIVE) { + if (abort_reason.ABRT_7B_ADDR_NOACK == .ACTIVE) { // Address byte wasn't acknowledged by any targets on the bus return TransactionError.DeviceNotPresent; - } else if (abort_reason.ABRT_TXDATA_NOACK.value == .ABRT_TXDATA_NOACK_GENERATED) { + } else if (abort_reason.ABRT_TXDATA_NOACK == .ABRT_TXDATA_NOACK_GENERATED) { // Address byte was acknowledged, but a data byte wasn't return TransactionError.NoAcknowledge; } else if (abort_reason.TX_FLUSH_CNT > 0) { @@ -353,7 +353,7 @@ pub const I2C = enum(u1) { // condition here? If so, additional code would be needed here // to take care of the abort. // As far as I can tell from the datasheet, no, this is not possible. - while (regs.IC_RAW_INTR_STAT.read().STOP_DET.value == .INACTIVE) { + while (regs.IC_RAW_INTR_STAT.read().STOP_DET == .INACTIVE) { hw.tight_loop_contents(); if (deadline.is_reached()) break; @@ -400,12 +400,12 @@ pub const I2C = enum(u1) { var iter = write_vec.iterator(); while (iter.next_element()) |element| { regs.IC_DATA_CMD.write(.{ - .RESTART = .{ .raw = 0 }, - .STOP = .{ .raw = @intFromBool(element.last) }, - .CMD = .{ .value = .WRITE }, + .RESTART = @enumFromInt(0), + .STOP = @enumFromInt(@intFromBool(element.last)), + .CMD = .WRITE, .DAT = element.value, - .FIRST_DATA_BYTE = .{ .value = .INACTIVE }, + .FIRST_DATA_BYTE = .INACTIVE, .padding = 0, }); // If an abort occurrs, the TX/RX FIFO is flushed, and subsequent writes to IC_DATA_CMD @@ -427,7 +427,7 @@ pub const I2C = enum(u1) { // Waits until everything in the TX FIFO is either successfully transmitted, or flushed // due to an abort. This functions because of TX_EMPTY_CTRL being enabled in apply(). - while (regs.IC_RAW_INTR_STAT.read().TX_EMPTY.value == .INACTIVE) { + while (regs.IC_RAW_INTR_STAT.read().TX_EMPTY == .INACTIVE) { if (deadline.is_reached()) { timed_out = true; break; @@ -479,12 +479,12 @@ pub const I2C = enum(u1) { var iter = read_vec.iterator(); while (iter.next_element_ptr()) |element| { regs.IC_DATA_CMD.write(.{ - .RESTART = .{ .raw = 0 }, - .STOP = .{ .raw = @intFromBool(element.last) }, - .CMD = .{ .value = .READ }, + .RESTART = @enumFromInt(0), + .STOP = @enumFromInt(@intFromBool(element.last)), + .CMD = .READ, .DAT = 0, - .FIRST_DATA_BYTE = .{ .value = .INACTIVE }, + .FIRST_DATA_BYTE = .INACTIVE, .padding = 0, }); @@ -551,12 +551,12 @@ pub const I2C = enum(u1) { var write_iter = write_vec.iterator(); send_loop: while (write_iter.next_element()) |element| { regs.IC_DATA_CMD.write(.{ - .RESTART = .{ .raw = 0 }, - .STOP = .{ .raw = 0 }, - .CMD = .{ .value = .WRITE }, + .RESTART = @enumFromInt(0), + .STOP = @enumFromInt(0), + .CMD = .WRITE, .DAT = element.value, - .FIRST_DATA_BYTE = .{ .value = .INACTIVE }, + .FIRST_DATA_BYTE = .INACTIVE, .padding = 0, }); // If an abort occurrs, the TX/RX FIFO is flushed, and subsequent writes to IC_DATA_CMD @@ -583,12 +583,12 @@ pub const I2C = enum(u1) { var read_iter = read_vec.iterator(); recv_loop: while (read_iter.next_element_ptr()) |element| { regs.IC_DATA_CMD.write(.{ - .RESTART = .{ .raw = @intFromBool(element.first) }, - .STOP = .{ .raw = @intFromBool(element.last) }, - .CMD = .{ .value = .READ }, + .RESTART = @enumFromInt(@intFromBool(element.first)), + .STOP = @enumFromInt(@intFromBool(element.last)), + .CMD = .READ, .DAT = 0, - .FIRST_DATA_BYTE = .{ .value = .INACTIVE }, + .FIRST_DATA_BYTE = .INACTIVE, .padding = 0, }); diff --git a/port/raspberrypi/rp2xxx/src/hal/random.zig b/port/raspberrypi/rp2xxx/src/hal/random.zig index e3117127a..7937bffa0 100644 --- a/port/raspberrypi/rp2xxx/src/hal/random.zig +++ b/port/raspberrypi/rp2xxx/src/hal/random.zig @@ -28,9 +28,9 @@ pub const Ascon = struct { pub fn init() @This() { // Ensure that the system clocks run from the XOSC and/or PLLs - const ref_src = peripherals.CLOCKS.CLK_REF_CTRL.read().SRC.value; - const sys_clk_src = peripherals.CLOCKS.CLK_SYS_CTRL.read().SRC.value; - const aux_src = peripherals.CLOCKS.CLK_SYS_CTRL.read().AUXSRC.value; + const ref_src = peripherals.CLOCKS.CLK_REF_CTRL.read().SRC; + const sys_clk_src = peripherals.CLOCKS.CLK_SYS_CTRL.read().SRC; + const aux_src = peripherals.CLOCKS.CLK_SYS_CTRL.read().AUXSRC; assert((ref_src != .rosc_clksrc_ph and sys_clk_src == .clk_ref) or (sys_clk_src == .clksrc_clk_sys_aux and aux_src != .rosc_clksrc)); @@ -68,10 +68,10 @@ pub const Ascon = struct { /// for security systems because it can be compromised, but it may be useful /// in less critical applications. fn rosc(buffer: []u8) void { - const rosc_state = peripherals.ROSC.CTRL.read().ENABLE.value; + const rosc_state = peripherals.ROSC.CTRL.read().ENABLE; // Enable the ROSC so it generates random bits for us - peripherals.ROSC.CTRL.modify(.{ .ENABLE = .{ .value = .ENABLE } }); - defer peripherals.ROSC.CTRL.modify(.{ .ENABLE = .{ .value = rosc_state } }); + peripherals.ROSC.CTRL.modify(.{ .ENABLE = .ENABLE }); + defer peripherals.ROSC.CTRL.modify(.{ .ENABLE = rosc_state }); var i: usize = 0; while (i < buffer.len) : (i += 1) { diff --git a/port/raspberrypi/rp2xxx/src/hal/usb.zig b/port/raspberrypi/rp2xxx/src/hal/usb.zig index 7c4d5693e..056a16b7c 100644 --- a/port/raspberrypi/rp2xxx/src/hal/usb.zig +++ b/port/raspberrypi/rp2xxx/src/hal/usb.zig @@ -51,6 +51,7 @@ pub const utf8ToUtf16Le = usb.utf8Toutf16Le; const BufferControlMmio = microzig.mmio.Mmio(@TypeOf(microzig.chip.peripherals.USB_DPRAM.EP0_IN_BUFFER_CONTROL).underlying_type); const EndpointControlMimo = microzig.mmio.Mmio(@TypeOf(peripherals.USB_DPRAM.EP1_IN_CONTROL).underlying_type); +const EndpointType = microzig.chip.types.peripherals.USB_DPRAM.EndpointType; const HardwareEndpoint = struct { configured: bool, @@ -159,7 +160,7 @@ pub fn F(comptime config: UsbConfig) type { peripherals.PLL_USB.PRIM.modify(.{ .POSTDIV1 = 5, .POSTDIV2 = 5 }); peripherals.PLL_USB.PWR.modify(.{ .POSTDIVPD = 0 }); // Switch usbclk to be derived from PLLUSB - peripherals.CLOCKS.CLK_USB_CTRL.modify(.{ .AUXSRC = .{ .value = .clksrc_pll_usb } }); + peripherals.CLOCKS.CLK_USB_CTRL.modify(.{ .AUXSRC = .clksrc_pll_usb }); // We now have the stable 48MHz reference clock required for USB: } @@ -179,7 +180,7 @@ pub fn F(comptime config: UsbConfig) type { rp2xxx_endpoints.get_buf_ctrl(@intCast(i), .In).?.write_raw(0); rp2xxx_endpoints.get_buf_ctrl(@intCast(i), .Out).?.write_raw(0); } - + // Mux the controller to the onboard USB PHY. I was surprised that there are // alternatives to this, but, there are. peripherals.USB.USB_MUXING.modify(.{ @@ -432,7 +433,7 @@ pub fn F(comptime config: UsbConfig) type { ep.endpoint_control.?.modify(.{ .ENABLE = 1, .INTERRUPT_PER_BUFF = 1, - .ENDPOINT_TYPE = .{ .raw = ep.transfer_type.as_number() }, + .ENDPOINT_TYPE = @as(EndpointType, @enumFromInt(ep.transfer_type.as_number())), .BUFFER_ADDRESS = rp2xxx_buffers.data_offset(ep.data_buffer), }); } @@ -505,4 +506,4 @@ pub fn F(comptime config: UsbConfig) type { }; } }; -} \ No newline at end of file +} diff --git a/tools/regz/src/Database.zig b/tools/regz/src/Database.zig index 016294bea..1b8a231eb 100644 --- a/tools/regz/src/Database.zig +++ b/tools/regz/src/Database.zig @@ -1839,6 +1839,128 @@ pub fn create_struct(db: *Database, opts: CreateStructOptions) !StructID { return struct_id; } +/// Returns the last part of the reference, and the beginning part of the +/// reference +fn get_ref_last_component(ref: []const u8) !struct { []const u8, ?[]const u8 } { + var it = std.mem.splitScalar(u8, ref, '.'); + var last: ?[]const u8 = null; + while (it.next()) |comp| { + last = comp; + } + + return if (last) |l| + if (l.len == ref.len) + .{ l, null } + else + .{ l, ref[0 .. ref.len - l.len - 1] } + else + error.EmptyRef; +} + +fn strip_ref_prefix(expected_prefix: []const u8, ref: []const u8) ![]const u8 { + var prefix_it = std.mem.splitScalar(u8, expected_prefix, '.'); + var ref_it = std.mem.splitScalar(u8, ref, '.'); + + while (prefix_it.next()) |prefix_comp| { + const ref_comp = ref_it.next() orelse return error.RefTooShort; + + if (!std.mem.eql(u8, prefix_comp, ref_comp)) + return error.RefPrefixNotExpected; + } + + const index = ref_it.index orelse return error.RefTooShort; + return ref[index..]; +} + +pub fn get_struct_ref(db: *Database, ref: []const u8) !StructID { + var arena = std.heap.ArenaAllocator.init(db.gpa); + defer arena.deinit(); + + const base_ref = try strip_ref_prefix("types.peripherals", ref); + const struct_name, const rest_ref = try get_ref_last_component(base_ref); + return if (rest_ref) |rest| blk: { + var it = std.mem.splitScalar(u8, rest, '.'); + const peripheral_name = it.next() orelse return error.NoPeripheral; + const peripheral_id = try db.get_peripheral_by_name(peripheral_name) orelse return error.NoPeripheral; + var struct_id = try db.get_peripheral_struct(peripheral_id); + if (it.index == null) { + return if (std.mem.eql(u8, struct_name, peripheral_name)) + struct_id + else + error.NoPeripheral; + } + + break :blk while (it.next()) |name| { + const struct_decl = try db.get_struct_decl_by_name(arena.allocator(), struct_id, name); + if (it.index == null and std.mem.eql(u8, struct_name, struct_decl.name)) + break struct_decl.struct_id; + + struct_id = struct_decl.struct_id; + } else error.RefNotFound; + } else blk: { + // just getting a peripheral + const peripheral_id = try db.get_peripheral_by_name(struct_name) orelse return error.NoPeripheral; + break :blk try db.get_peripheral_struct(peripheral_id); + }; +} + +pub fn get_enum_ref(db: *Database, ref: []const u8) !EnumID { + var arena = std.heap.ArenaAllocator.init(db.gpa); + defer arena.deinit(); + + // An enum that can be referenced has a struct as a parent + const enum_name, const struct_ref = try get_ref_last_component(ref); + const struct_id = try db.get_struct_ref(struct_ref orelse return error.InvalidRef); + + // TODO: create a `get_enum_id_by_name()` function + const e = try db.get_enum_by_name(arena.allocator(), struct_id, enum_name); + return e.id; +} + +pub fn get_register_ref(db: *Database, ref: []const u8) !RegisterID { + var arena = std.heap.ArenaAllocator.init(db.gpa); + defer arena.deinit(); + + const register_name, const struct_ref = try get_ref_last_component(ref); + const struct_id = try db.get_struct_ref(struct_ref orelse return error.InvalidRef); + const register = try db.get_register_by_name(arena.allocator(), struct_id, register_name); + return register.id; +} + +pub fn set_register_field_enum_id(db: *Database, register_id: RegisterID, field_name: []const u8, enum_id: EnumID) !void { + try db.exec( + \\UPDATE struct_fields + \\SET enum_id = ? + \\WHERE struct_id = ( + \\ SELECT struct_id + \\ FROM registers + \\ WHERE id = ? + \\) + \\AND name = ?; + , .{ + .enum_id = enum_id, + .register_id = register_id, + .name = field_name, + }); + + log.debug("set_register_field_enum_id: register_id={} field_name={s} enum_id={}", .{ + register_id, + field_name, + enum_id, + }); +} + +pub fn cleanup_unused_enums(db: *Database) !void { + try db.exec( + \\DELETE FROM enums + \\WHERE id NOT IN ( + \\ SELECT DISTINCT enum_id + \\ FROM struct_fields + \\ WHERE enum_id IS NOT NULL + \\) + , .{}); +} + pub fn apply_patch(db: *Database, ndjson: []const u8) !void { var list = std.ArrayList(std.json.Parsed(Patch)).init(db.gpa); defer { @@ -1852,6 +1974,35 @@ pub fn apply_patch(db: *Database, ndjson: []const u8) !void { errdefer p.deinit(); try list.append(p); } + + for (list.items) |patch| { + switch (patch.value) { + .add_enum => |add_enum| { + const struct_id = try db.get_struct_ref(add_enum.parent); + + const enum_id = try db.create_enum(struct_id, .{ + .name = add_enum.@"enum".name, + .description = add_enum.@"enum".description, + .size_bits = add_enum.@"enum".bitsize, + }); + + for (add_enum.@"enum".fields) |enum_field| { + try db.add_enum_field(enum_id, .{ + .name = enum_field.name, + .description = enum_field.description, + .value = enum_field.value, + }); + } + }, + .set_enum_type => |set_enum_type| { + const enum_id = try db.get_enum_ref(set_enum_type.to); + const field_name, const register_ref = try get_ref_last_component(set_enum_type.of); + const register_id = try db.get_register_ref(register_ref orelse return error.InvalidRef); + try db.set_register_field_enum_id(register_id, field_name, enum_id); + try db.cleanup_unused_enums(); + }, + } + } } pub fn to_zig(db: *Database, out_writer: anytype) !void { diff --git a/tools/regz/src/gen.zig b/tools/regz/src/gen.zig index 3bd86f3e9..16a2961a0 100644 --- a/tools/regz/src/gen.zig +++ b/tools/regz/src/gen.zig @@ -772,45 +772,35 @@ fn write_fields( if (e.name) |enum_name| { if (e.struct_id == null or try db.enum_has_name_collision(enum_id)) { try writer.print( - \\{}: packed union {{ - \\ raw: u{}, - \\ value: enum(u{}) {{ + \\{}: enum(u{}) {{ \\ , .{ std.zig.fmtId(field.name), e.size_bits, - e.size_bits, }); try write_enum_fields(db, arena, &e, writer); - try writer.writeAll("},\n},\n"); + try writer.writeAll("},\n"); } else { try writer.print( - \\{}: packed union {{ - \\ raw: u{}, - \\ value: {}, - \\}}, + \\{}: {}, \\ , .{ std.zig.fmtId(field.name), - field.size_bits, std.zig.fmtId(enum_name), }); } } else { try writer.print( - \\{}: packed union {{ - \\ raw: u{}, - \\ value: enum(u{}) {{ + \\{}: enum(u{}) {{ \\ , .{ std.zig.fmtId(field.name), e.size_bits, - e.size_bits, }); try write_enum_fields(db, arena, &e, writer); - try writer.writeAll("},\n},\n"); + try writer.writeAll("},\n"); } } else { try writer.print("{}: u{},\n", .{ std.zig.fmtId(field.name), field.get_size_bits() }); @@ -1038,10 +1028,7 @@ test "gen.field with named enum" { \\ }; \\ \\ TEST_REGISTER: mmio.Mmio(packed struct(u8) { - \\ TEST_FIELD: packed union { - \\ raw: u4, - \\ value: TEST_ENUM, - \\ }, + \\ TEST_FIELD: TEST_ENUM, \\ padding: u4, \\ }), \\ }; @@ -1067,13 +1054,10 @@ test "gen.field with anonymous enum" { \\ pub const peripherals = struct { \\ pub const TEST_PERIPHERAL = extern struct { \\ TEST_REGISTER: mmio.Mmio(packed struct(u8) { - \\ TEST_FIELD: packed union { - \\ raw: u4, - \\ value: enum(u4) { - \\ TEST_ENUM_FIELD1 = 0x0, - \\ TEST_ENUM_FIELD2 = 0x1, - \\ _, - \\ }, + \\ TEST_FIELD: enum(u4) { + \\ TEST_ENUM_FIELD1 = 0x0, + \\ TEST_ENUM_FIELD2 = 0x1, + \\ _, \\ }, \\ padding: u4, \\ }), @@ -1423,21 +1407,15 @@ test "gen.name collisions in enum name cause them to be anonymous" { \\ pub const peripherals = struct { \\ pub const TEST_PERIPHERAL = extern struct { \\ TEST_REGISTER: mmio.Mmio(packed struct(u8) { - \\ TEST_FIELD1: packed union { - \\ raw: u4, - \\ value: enum(u4) { - \\ TEST_ENUM_FIELD1 = 0x0, - \\ TEST_ENUM_FIELD2 = 0x1, - \\ _, - \\ }, + \\ TEST_FIELD1: enum(u4) { + \\ TEST_ENUM_FIELD1 = 0x0, + \\ TEST_ENUM_FIELD2 = 0x1, + \\ _, \\ }, - \\ TEST_FIELD2: packed union { - \\ raw: u4, - \\ value: enum(u4) { - \\ TEST_ENUM_FIELD1 = 0x0, - \\ TEST_ENUM_FIELD2 = 0x1, - \\ _, - \\ }, + \\ TEST_FIELD2: enum(u4) { + \\ TEST_ENUM_FIELD1 = 0x0, + \\ TEST_ENUM_FIELD2 = 0x1, + \\ _, \\ }, \\ }), \\ }; @@ -1465,12 +1443,9 @@ test "gen.pick one enum field in value collisions" { \\ pub const peripherals = struct { \\ pub const TEST_PERIPHERAL = extern struct { \\ TEST_REGISTER: mmio.Mmio(packed struct(u8) { - \\ TEST_FIELD: packed union { - \\ raw: u4, - \\ value: enum(u4) { - \\ TEST_ENUM_FIELD1 = 0x0, - \\ _, - \\ }, + \\ TEST_FIELD: enum(u4) { + \\ TEST_ENUM_FIELD1 = 0x0, + \\ _, \\ }, \\ padding: u4, \\ }), @@ -1497,12 +1472,9 @@ test "gen.pick one enum field in name collisions" { \\ pub const peripherals = struct { \\ pub const TEST_PERIPHERAL = extern struct { \\ TEST_REGISTER: mmio.Mmio(packed struct(u8) { - \\ TEST_FIELD: packed union { - \\ raw: u4, - \\ value: enum(u4) { - \\ TEST_ENUM_FIELD1 = 0x0, - \\ _, - \\ }, + \\ TEST_FIELD: enum(u4) { + \\ TEST_ENUM_FIELD1 = 0x0, + \\ _, \\ }, \\ padding: u4, \\ }),