diff --git a/tools/regz/src/Database.zig b/tools/regz/src/Database.zig index 4b85170..adc3371 100644 --- a/tools/regz/src/Database.zig +++ b/tools/regz/src/Database.zig @@ -7,6 +7,7 @@ const Peripheral = @import("Peripheral.zig"); const Register = @import("Register.zig"); const Field = @import("Field.zig"); const Enumeration = @import("Enumeration.zig"); +const cmsis = @import("cmsis.zig"); pub const Access = svd.Access; const assert = std.debug.assert; @@ -15,11 +16,11 @@ const Allocator = std.mem.Allocator; const Database = @This(); -const PeripheralIndex = u32; -const ClusterIndex = u32; -const RegisterIndex = u32; -const FieldIndex = u32; -const EnumIndex = u32; +pub const PeripheralIndex = u32; +pub const ClusterIndex = u32; +pub const RegisterIndex = u32; +pub const FieldIndex = u32; +pub const EnumIndex = u32; fn IndexRange(comptime Index: type) type { return struct { @@ -146,6 +147,10 @@ pub fn initFromSvd(allocator: Allocator, doc: *xml.Doc) !Database { else null; + if (db.cpu) |cpu| if (cpu.name) |cpu_name| + if (svd.CpuName.parse(cpu_name)) |cpu_type| + try cmsis.addCoreRegisters(&db, cpu_type); + var named_derivations = Derivations([]const u8){}; defer named_derivations.deinit(allocator); @@ -539,6 +544,8 @@ pub fn initFromAtdf(allocator: Allocator, doc: *xml.Doc) !Database { .nvic_prio_bits = 0, .vendor_systick_config = false, .device_num_interrupts = null, + .vtor_present = false, + .mpu_present = false, }; const device_nodes: *xml.Node = device_it.?.children orelse continue; @@ -853,42 +860,42 @@ pub fn toZig(db: *Database, out_writer: anytype) !void { continue; } - const reg_range = db.registers_in_peripherals.get(peripheral_idx).?; - const registers = db.registers.items[reg_range.begin..reg_range.end]; - if (registers.len != 0 or has_clusters) { - if (peripheral.description) |description| if (!useless_descriptions.has(description)) { - try writer.writeByte('\n'); - try writeDescription(db.arena.child_allocator, writer, description); - }; + if (peripheral.description) |description| if (!useless_descriptions.has(description)) { + try writer.writeByte('\n'); + try writeDescription(db.arena.child_allocator, writer, description); + }; + + try writer.print(" pub const {s} = struct {{\n", .{std.zig.fmtId(peripheral.name)}); + if (peripheral.base_addr) |base_addr| + try writer.print(" pub const base_address = 0x{x};\n", .{base_addr}); - try writer.print(" pub const {s} = struct {{\n", .{std.zig.fmtId(peripheral.name)}); - if (peripheral.base_addr) |base_addr| - try writer.print(" pub const base_address = 0x{x};\n", .{base_addr}); + if (peripheral.version) |version| + try writer.print(" pub const version = \"{s}\";\n", .{version}); - if (peripheral.version) |version| - try writer.print(" pub const version = \"{s}\";\n", .{version}); + if (db.registers_in_peripherals.get(peripheral_idx)) |reg_range| { + const registers = db.registers.items[reg_range.begin..reg_range.end]; for (registers) |_, range_offset| { const reg_idx = @intCast(RegisterIndex, reg_range.begin + range_offset); const register = try db.getRegister(reg_idx); - try db.genZigRegister(writer, peripheral.base_addr, reg_idx, register, .namespaced); + try db.genZigRegister(writer, peripheral.base_addr, null, reg_idx, register, .namespaced); } + } - if (has_clusters) { - for (db.clusters_in_peripherals.items) |cip| { - if (cip.peripheral_idx == peripheral_idx) { - try db.genZigCluster(writer, peripheral.base_addr, cip.cluster_idx, .namespaced); - } - } - - for (db.clusters_in_clusters.items) |cic| { - const nested = db.clusters.items[cic.child_idx]; - std.log.warn("nested clusters not supported yet: {s}", .{nested.name}); + if (has_clusters) { + for (db.clusters_in_peripherals.items) |cip| { + if (cip.peripheral_idx == peripheral_idx) { + try db.genZigCluster(writer, peripheral.base_addr, cip.cluster_idx, .namespaced); } } - try writer.writeAll(" };\n"); + for (db.clusters_in_clusters.items) |cic| { + const nested = db.clusters.items[cic.child_idx]; + std.log.warn("nested clusters not supported yet: {s}", .{nested.name}); + } } + + try writer.writeAll(" };\n"); } try writer.writeAll("};\n"); @@ -938,12 +945,11 @@ fn genZigCluster( try writer.print("pub const {s} = @ptrCast(*volatile [{}]packed struct {{", .{ name, dimension.dim }); - // TODO: check address offset of register wrt the cluster var bits: usize = 0; 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); + try db.genZigRegister(writer, base_addr, cluster.addr_offset, reg_idx, register, .contained); bits += register.size.?; } @@ -967,7 +973,7 @@ fn genZigCluster( 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, .namespaced); + try db.genZigRegister(writer, base_addr, cluster.addr_offset, reg_idx, register, .namespaced); } try writer.writeAll("};\n"); @@ -1253,6 +1259,7 @@ fn genZigRegister( db: *Database, writer: anytype, base_addr: ?usize, + cluster_offset: ?usize, reg_idx: RegisterIndex, register: Register, nesting: Nesting, @@ -1283,7 +1290,12 @@ fn genZigRegister( try writer.writeByte('\n'); if (nesting == .namespaced) { - const addr = if (base_addr) |base| base + addr_offset else addr_offset; + var addr: u64 = addr_offset; + if (cluster_offset) |offset| + addr += offset; + if (base_addr) |base| + addr += base; + try writer.print("/// address: 0x{x}\n", .{addr}); } @@ -1295,7 +1307,13 @@ fn genZigRegister( name, register.size.?, base_addr != null, - addr_offset, + if (nesting == .namespaced) + if (cluster_offset) |offset| + offset + addr_offset + else + addr_offset + else + addr_offset, field_range, "", nesting, @@ -1317,7 +1335,12 @@ fn genZigRegister( try writer.writeByte('\n'); if (nesting == .namespaced) { - const addr = if (base_addr) |base| base + addr_offset else addr_offset; + var addr: u64 = addr_offset; + if (cluster_offset) |offset| + addr += offset; + if (base_addr) |base| + addr += base; + try writer.print("/// address: 0x{x}\n", .{addr}); } @@ -1329,7 +1352,13 @@ fn genZigRegister( name, register.size.?, base_addr != null, - addr_offset, + if (nesting == .namespaced) + if (cluster_offset) |offset| + offset + addr_offset + else + addr_offset + else + addr_offset, field_range, "", nesting, @@ -1372,7 +1401,12 @@ fn genZigRegister( const name = try std.mem.replaceOwned(u8, db.arena.allocator(), register.name, "[%s]", ""); try writer.writeByte('\n'); if (nesting == .namespaced) { - const addr = if (base_addr) |base| base + register.addr_offset else register.addr_offset; + var addr = register.addr_offset; + if (cluster_offset) |offset| + addr += offset; + if (base_addr) |base| + addr += base; + try writer.print("/// address: 0x{x}\n", .{addr}); } @@ -1384,7 +1418,13 @@ fn genZigRegister( name, register.size.?, base_addr != null, - register.addr_offset, + if (nesting == .namespaced) + if (cluster_offset) |offset| + offset + register.addr_offset + else + register.addr_offset + else + register.addr_offset, field_range, array_prefix, nesting, @@ -1527,6 +1567,45 @@ pub fn getRegister( }; } +pub fn addClusterToPeripheral( + db: *Database, + peripheral: PeripheralIndex, + cluster: svd.Cluster, +) !ClusterIndex { + const cluster_idx = @intCast(ClusterIndex, db.clusters.items.len); + try db.clusters.append(db.gpa, cluster); + try db.clusters_in_peripherals.append(db.gpa, .{ + .peripheral_idx = peripheral, + .cluster_idx = cluster_idx, + }); + + // TODO: register properties and dimensions + return cluster_idx; +} + +pub fn addFieldsToRegister(db: *Database, register: RegisterIndex, fields: []const Field) !void { + const begin = @intCast(FieldIndex, db.fields.items.len); + try db.fields.appendSlice(db.gpa, fields); + try db.fields_in_registers.put(db.gpa, register, .{ + .begin = begin, + .end = @intCast(FieldIndex, db.fields.items.len), + }); +} + +pub fn addRegistersToCluster(db: *Database, cluster: ClusterIndex, registers: []const Register) !IndexRange(RegisterIndex) { + const begin = @intCast(RegisterIndex, db.registers.items.len); + try db.registers.appendSlice(db.gpa, registers); + + const range = IndexRange(RegisterIndex){ + .begin = begin, + .end = @intCast(RegisterIndex, db.registers.items.len), + }; + try db.registers_in_clusters.put(db.gpa, cluster, range); + + // TODO: register properties and dimensions + return range; +} + fn Derivations(comptime T: type) type { return struct { enumerations: std.AutoHashMapUnmanaged(EnumIndex, T) = .{}, diff --git a/tools/regz/src/Field.zig b/tools/regz/src/Field.zig index a411fa4..f37309c 100644 --- a/tools/regz/src/Field.zig +++ b/tools/regz/src/Field.zig @@ -1,8 +1,8 @@ name: []const u8, -description: ?[]const u8, +description: ?[]const u8 = null, offset: u8, width: u8, -access: ?@import("svd.zig").Access, +access: ?@import("svd.zig").Access = null, pub fn lessThan(_: void, lhs: @This(), rhs: @This()) bool { return if (lhs.offset == rhs.offset) diff --git a/tools/regz/src/Register.zig b/tools/regz/src/Register.zig index 7bc25bd..ede0d77 100644 --- a/tools/regz/src/Register.zig +++ b/tools/regz/src/Register.zig @@ -1,12 +1,12 @@ const std = @import("std"); name: []const u8, -description: ?[]const u8, +description: ?[]const u8 = null, addr_offset: usize, -size: ?usize, -access: ?@import("svd.zig").Access, -reset_value: ?u64, -reset_mask: ?u64, +size: ?usize = null, +access: ?@import("svd.zig").Access = null, +reset_value: ?u64 = null, +reset_mask: ?u64 = null, pub fn format( register: @This(), diff --git a/tools/regz/src/cmsis.zig b/tools/regz/src/cmsis.zig new file mode 100644 index 0000000..c7cc437 --- /dev/null +++ b/tools/regz/src/cmsis.zig @@ -0,0 +1,82 @@ +const std = @import("std"); +const svd = @import("svd.zig"); +const Database = @import("Database.zig"); + +const cores = struct { + const cortex_m0plus = @import("cmsis/cortex_m0plus.zig"); +}; + +fn addSysTickRegisters(db: *Database, scs: Database.PeripheralIndex) !void { + const systick = try db.addClusterToPeripheral(scs, .{ + .name = "SysTick", + .description = "System Tick Timer", + .addr_offset = 0x10, + }); + + const regs = try db.addRegistersToCluster(systick, &.{ + .{ + .name = "CTRL", + .description = "SysTick Control and Status Register", + .addr_offset = 0x0, + }, + .{ + .name = "LOAD", + .description = "SysTick Reload Value Register", + .addr_offset = 0x4, + }, + .{ + .name = "VAL", + .description = "SysTick Current Value Register", + .addr_offset = 0x8, + }, + .{ + .name = "CALIB", + .description = "SysTick Calibration Register", + .access = .read_only, + .addr_offset = 0xc, + }, + }); + + const ctrl = regs.begin; + try db.addFieldsToRegister(ctrl, &.{ + .{ .name = "ENABLE", .offset = 0, .width = 1 }, + .{ .name = "TICKINT", .offset = 1, .width = 1 }, + .{ .name = "CLKSOURCE", .offset = 2, .width = 1 }, + .{ .name = "COUNTFLAG", .offset = 16, .width = 1 }, + }); + + const load = regs.begin + 1; + try db.addFieldsToRegister(load, &.{ + .{ .name = "RELOAD", .offset = 0, .width = 24 }, + }); + + const val = regs.begin + 2; + try db.addFieldsToRegister(val, &.{ + .{ .name = "CURRENT", .offset = 0, .width = 24 }, + }); + + const calib = regs.begin + 3; + try db.addFieldsToRegister(calib, &.{ + .{ .name = "TENMS", .offset = 0, .width = 24 }, + .{ .name = "SKEW", .offset = 30, .width = 1 }, + .{ .name = "NOREF", .offset = 31, .width = 1 }, + }); +} + +pub fn addCoreRegisters(db: *Database, cpu_name: svd.CpuName) !void { + const scs = @intCast(Database.PeripheralIndex, db.peripherals.items.len); + try db.peripherals.append(db.gpa, .{ + .name = "SCS", + .version = null, + .description = "System Control Space", + .base_addr = 0xe000e000, + }); + try db.register_properties.peripheral.size.put(db.gpa, scs, 32); + + if (db.cpu) |cpu| if (!cpu.vendor_systick_config) + try addSysTickRegisters(db, scs); + + inline for (@typeInfo(cores).Struct.decls) |decl| + if (cpu_name == @field(svd.CpuName, decl.name)) + try @field(cores, decl.name).addCoreRegisters(db, scs); +} diff --git a/tools/regz/src/cmsis/cortex_m0plus.zig b/tools/regz/src/cmsis/cortex_m0plus.zig new file mode 100644 index 0000000..84ae8af --- /dev/null +++ b/tools/regz/src/cmsis/cortex_m0plus.zig @@ -0,0 +1,241 @@ +const std = @import("std"); +const Database = @import("../Database.zig"); +const Register = @import("../Register.zig"); + +pub fn addCoreRegisters(db: *Database, scs: Database.PeripheralIndex) !void { + _ = db; + _ = scs; + + const nvic = try db.addClusterToPeripheral(scs, .{ + .name = "NVIC", + .description = "Nested Vectored Interrupt Controller", + .addr_offset = 0x100, + }); + + _ = try db.addRegistersToCluster(nvic, &.{ + .{ + .name = "ISER", + .description = "Interrupt Set Enable Register", + .addr_offset = 0x000, + }, + .{ + .name = "ICER", + .description = "Interrupt Clear Enable Register", + .addr_offset = 0x80, + }, + .{ + .name = "ISPR", + .description = "Interrupt Set Pending Register", + .addr_offset = 0x100, + }, + .{ + .name = "ICPR", + .description = "Interrupt Clear Pending Register", + .addr_offset = 0x180, + }, + .{ + .name = "IP", + .description = "Interrupt Priority Register", + .addr_offset = 0x300, + //.dimension = .{ + // .dim = 8, + //}, + }, + }); + + const scb = try db.addClusterToPeripheral(scs, .{ + .name = "SCB", + .description = "System Control Block", + .addr_offset = 0xd00, + }); + + var scb_regs = std.ArrayList(Register).init(db.gpa); + defer scb_regs.deinit(); + + try scb_regs.appendSlice(&.{ + .{ + .name = "CPUID", + .addr_offset = 0x000, + .access = .read_only, + }, + .{ + .name = "ICSR", + .description = "Interrupt Control and State Register", + .addr_offset = 0x004, + }, + .{ + .name = "AIRCR", + .description = "Application Interrupt and Reset Control Register", + .addr_offset = 0x00c, + }, + .{ + .name = "SCR", + .description = "System Control Register", + .addr_offset = 0x010, + }, + .{ + .name = "CCR", + .description = "Configuration Control Register", + .addr_offset = 0x014, + }, + .{ + .name = "SHP", + .description = "System Handlers Priority Registers. [0] is RESERVED", + .addr_offset = 0x01c, + //.dimension = .{ + // .dim = 2, + //}, + }, + .{ + .name = "SHCSR", + .description = "System Handler Control and State Register", + .addr_offset = 0x024, + }, + }); + + if (db.cpu) |cpu| if (cpu.vtor_present) { + try scb_regs.append(.{ + .name = "VTOR", + .description = "Vector Table Offset Register", + .addr_offset = 0x08, + }); + }; + + var regs = try db.addRegistersToCluster(scb, scb_regs.items); + + const cpuid = regs.begin; + try db.addFieldsToRegister(cpuid, &.{ + .{ .name = "REVISION", .offset = 0, .width = 4 }, + .{ .name = "PARTNO", .offset = 4, .width = 12 }, + .{ .name = "ARCHITECTURE", .offset = 16, .width = 4 }, + .{ .name = "VARIANT", .offset = 20, .width = 4 }, + .{ .name = "IMPLEMENTER", .offset = 24, .width = 8 }, + }); + + const icsr = regs.begin + 1; + try db.addFieldsToRegister(icsr, &.{ + .{ .name = "VECTACTIVE", .offset = 0, .width = 9 }, + .{ .name = "VECTPENDING", .offset = 12, .width = 9 }, + .{ .name = "ISRPENDING", .offset = 22, .width = 1 }, + .{ .name = "ISRPREEMPT", .offset = 23, .width = 1 }, + .{ .name = "PENDSTCLR", .offset = 25, .width = 1 }, + .{ .name = "PENDSTSET", .offset = 26, .width = 1 }, + .{ .name = "PENDSVCLR", .offset = 27, .width = 1 }, + .{ .name = "PENDSVSET", .offset = 28, .width = 1 }, + .{ .name = "NMIPENDSET", .offset = 31, .width = 1 }, + }); + + const aircr = regs.begin + 2; + try db.addFieldsToRegister(aircr, &.{ + .{ .name = "VECTCLRACTIVE", .offset = 1, .width = 1 }, + .{ .name = "SYSRESETREQ", .offset = 2, .width = 1 }, + .{ .name = "ENDIANESS", .offset = 15, .width = 1 }, + .{ .name = "VECTKEY", .offset = 16, .width = 16 }, + }); + + const scr = regs.begin + 3; + try db.addFieldsToRegister(scr, &.{ + .{ .name = "SLEEPONEXIT", .offset = 1, .width = 1 }, + .{ .name = "SLEEPDEEP", .offset = 2, .width = 1 }, + .{ .name = "SEVONPEND", .offset = 4, .width = 1 }, + }); + + const ccr = regs.begin + 4; + try db.addFieldsToRegister(ccr, &.{ + .{ .name = "UNALIGN_TRP", .offset = 3, .width = 1 }, + .{ .name = "STKALIGN", .offset = 9, .width = 1 }, + }); + + const shcsr = regs.begin + 6; + try db.addFieldsToRegister(shcsr, &.{ + .{ .name = "SVCALLPENDED", .offset = 15, .width = 1 }, + }); + + if (db.cpu) |cpu| if (cpu.vtor_present) { + const vtor = regs.begin + 7; + try db.addFieldsToRegister(vtor, &.{.{ + .name = "TBLOFF", + .offset = 8, + .width = 24, + }}); + }; + + if (db.cpu) |cpu| if (cpu.mpu_present) + try addMpuRegisters(db, scs); +} + +fn addMpuRegisters(db: *Database, scs: Database.PeripheralIndex) !void { + const mpu = try db.addClusterToPeripheral(scs, .{ + .name = "MPU", + .description = "Memory Protection Unit", + .addr_offset = 0xd90, + }); + + const regs = try db.addRegistersToCluster(mpu, &.{ + .{ + .name = "TYPE", + .description = "MPU Type Register", + .addr_offset = 0x00, + .access = .read_only, + }, + .{ + .name = "CTRL", + .description = "MPU Control Register", + .addr_offset = 0x04, + }, + .{ + .name = "RNR", + .description = "MPU Region RNRber Register", + .addr_offset = 0x08, + }, + .{ + .name = "RBAR", + .description = "MPU Region Base Address Register", + .addr_offset = 0x0c, + }, + .{ + .name = "RASR", + .description = "MPU Region Attribute and Size Register", + .addr_offset = 0x10, + }, + }); + + const type_reg = regs.begin; + try db.addFieldsToRegister(type_reg, &.{ + .{ .name = "SEPARATE", .offset = 0, .width = 1 }, + .{ .name = "DREGION", .offset = 8, .width = 8 }, + .{ .name = "IREGION", .offset = 16, .width = 8 }, + }); + + const ctrl = regs.begin + 1; + try db.addFieldsToRegister(ctrl, &.{ + .{ .name = "ENABLE", .offset = 0, .width = 1 }, + .{ .name = "HFNMIENA", .offset = 1, .width = 1 }, + .{ .name = "PRIVDEFENA", .offset = 2, .width = 1 }, + }); + + const rnr = regs.begin + 2; + try db.addFieldsToRegister(rnr, &.{ + .{ .name = "REGION", .offset = 0, .width = 8 }, + }); + + const rbar = regs.begin + 3; + try db.addFieldsToRegister(rbar, &.{ + .{ .name = "REGION", .offset = 0, .width = 4 }, + .{ .name = "VALID", .offset = 4, .width = 1 }, + .{ .name = "ADDR", .offset = 8, .width = 24 }, + }); + + const rasr = regs.begin + 4; + try db.addFieldsToRegister(rasr, &.{ + .{ .name = "ENABLE", .offset = 0, .width = 1 }, + .{ .name = "SIZE", .offset = 1, .width = 5 }, + .{ .name = "SRD", .offset = 8, .width = 8 }, + .{ .name = "B", .offset = 16, .width = 1 }, + .{ .name = "C", .offset = 17, .width = 1 }, + .{ .name = "S", .offset = 18, .width = 1 }, + .{ .name = "TEX", .offset = 19, .width = 3 }, + .{ .name = "AP", .offset = 24, .width = 3 }, + .{ .name = "XN", .offset = 28, .width = 1 }, + }); +} diff --git a/tools/regz/src/svd.zig b/tools/regz/src/svd.zig index 19928ec..59204fc 100644 --- a/tools/regz/src/svd.zig +++ b/tools/regz/src/svd.zig @@ -145,7 +145,7 @@ pub const Cpu = struct { name: ?[]const u8, revision: []const u8, endian: Endian, - //mpu_present: bool, + mpu_present: bool, //fpu_present: bool, //fpu_dp: bool, //dsp_present: bool, @@ -153,7 +153,7 @@ pub const Cpu = struct { //dcache_present: bool, //itcm_present: bool, //dtcm_present: bool, - //vtor_present: bool, + vtor_present: bool, nvic_prio_bits: usize, vendor_systick_config: bool, device_num_interrupts: ?usize, @@ -171,6 +171,8 @@ pub const Cpu = struct { try std.fmt.parseInt(usize, size_str, 0) else null, + .vtor_present = (try xml.parseBoolean(arena.child_allocator, nodes, "vtorPresent")) orelse false, + .mpu_present = (try xml.parseBoolean(arena.child_allocator, nodes, "mpuPresent")) orelse false, }; } };