Skip to content

Commit b4443ff

Browse files
authored
regz: Standard format for chip properties (#757)
1 parent 1181b8b commit b4443ff

File tree

6 files changed

+161
-59
lines changed

6 files changed

+161
-59
lines changed

core/src/cpus/cortex_m.zig

Lines changed: 60 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -737,23 +737,13 @@ pub const startup_logic = struct {
737737
: .{ .memory = true, .r0 = true, .r1 = true });
738738
}
739739

740-
if (fpu_present and microzig.options.cpu.enable_fpu) {
740+
if (microzig.options.cpu.enable_fpu and has_fpu) {
741741
enable_fpu();
742-
} else if (!fpu_present and microzig.options.cpu.enable_fpu) {
742+
} else if (microzig.options.cpu.enable_fpu and !has_fpu) {
743743
@compileError(
744-
\\FPU enable requested though the chip doesn't appear to have an
745-
\\FPU. If your chip does have an FPU please add the `fpu_present`
746-
\\equal to `true` property to your chip file, either manually or via
747-
\\patches. If you want to use patches, you can use something like
748-
\\this:
749-
\\```
750-
\\.{ .set_device_property = .{
751-
\\ .device_name = "CHIP_NAME",
752-
\\ .key = "fpu_present",
753-
\\ .value = "true"
754-
\\} },
755-
\\```
756-
);
744+
\\FPU enable requested though the chip doesn't appear to have an FPU.
745+
\\
746+
++ fpu_error_helper_message);
757747
}
758748

759749
if (@hasField(types.peripherals.SystemControlBlock, "SHCSR")) {
@@ -1044,17 +1034,43 @@ const scb_base = scs_base + core.scb_base_offset;
10441034
const mpu_base = scs_base + 0x0D90;
10451035
const fpu_base = scs_base + 0x0F34;
10461036

1047-
// TODO: will have to standardize this with regz code generation
1048-
const mpu_present = @hasDecl(microzig.chip, "properties") and
1049-
@hasDecl(microzig.chip.properties, "mpu_present") and
1050-
is_property_true(microzig.chip.properties.mpu_present);
1051-
const fpu_present = @hasDecl(microzig.chip, "properties") and
1052-
@hasDecl(microzig.chip.properties, "fpu_present") and
1053-
is_property_true(microzig.chip.properties.fpu_present);
1054-
1055-
fn is_property_true(value: []const u8) bool {
1056-
return std.mem.eql(u8, value, "true") or std.mem.eql(u8, value, "1");
1057-
}
1037+
const has_mpu = microzig.chip.properties.has_mpu orelse
1038+
@compileError(
1039+
\\It is uncertain if this chip has an MPU or not.
1040+
\\
1041+
++ mpu_error_helper_message);
1042+
1043+
const has_fpu = microzig.chip.properties.has_fpu orelse
1044+
@compileError(
1045+
\\It is uncertain if this chip has an FPU or not.
1046+
\\
1047+
++ fpu_error_helper_message);
1048+
1049+
const mpu_error_helper_message =
1050+
\\If you are certain the chip does have an MPU, please set `cpu.mpuPresent`
1051+
\\(or `__MPU_PRESENT`) to `true` (or `1`) in your chip file, either manually
1052+
\\or via patches. If you want to use patches, you can use something like this:
1053+
\\```
1054+
\\.{ .set_device_property = .{
1055+
\\ .device_name = "CHIP_NAME",
1056+
\\ .key = "cpu.mpuPresent",
1057+
\\ .value = "true"
1058+
\\} },
1059+
\\```
1060+
;
1061+
1062+
const fpu_error_helper_message =
1063+
\\If you are certain your chip does have an FPU, please set `cpu.fpuPresent`
1064+
\\(or `__FPU_PRESENT`) to `true` (or `1`) in your chip file, either manually
1065+
\\or via patches. If you want to use patches, you can use something like this:
1066+
\\```
1067+
\\.{ .set_device_property = .{
1068+
\\ .device_name = "CHIP_NAME",
1069+
\\ .key = "cpu.fpuPresent",
1070+
\\ .value = "true"
1071+
\\} },
1072+
\\```
1073+
;
10581074

10591075
const core = blk: {
10601076
break :blk switch (cortex_m) {
@@ -1078,10 +1094,13 @@ pub const peripherals = struct {
10781094
pub const scb: *volatile types.peripherals.SystemControlBlock = @ptrFromInt(scb_base);
10791095

10801096
/// Floating Point Unit (FPU).
1081-
pub const fpu: *volatile types.peripherals.FloatingPointUnit = if (fpu_present)
1097+
pub const fpu: *volatile types.peripherals.FloatingPointUnit = if (has_fpu)
10821098
@ptrFromInt(fpu_base)
10831099
else
1084-
@compileError("this CPU does not have an FPU");
1100+
@compileError(
1101+
\\This chip doesn't appear to have an FPU.
1102+
\\
1103+
++ fpu_error_helper_message);
10851104

10861105
/// Nested Vector Interrupt Controller (NVIC).
10871106
pub const nvic: *volatile types.peripherals.NestedVectorInterruptController = @ptrFromInt(nvic_base);
@@ -1090,10 +1109,13 @@ pub const peripherals = struct {
10901109
pub const systick: *volatile types.peripherals.SysTick = @ptrFromInt(systick_base);
10911110

10921111
/// Memory Protection Unit (MPU).
1093-
pub const mpu: *volatile types.peripherals.MemoryProtectionUnit = if (mpu_present)
1112+
pub const mpu: *volatile types.peripherals.MemoryProtectionUnit = if (has_mpu)
10941113
@ptrFromInt(mpu_base)
10951114
else
1096-
@compileError("this CPU does not have an MPU");
1115+
@compileError(
1116+
\\This chip doesn't appear to have an MPU.
1117+
\\
1118+
++ mpu_error_helper_message);
10971119

10981120
pub const dbg: (if (@hasDecl(core, "DebugRegisters"))
10991121
*volatile core.DebugRegisters
@@ -1120,7 +1142,10 @@ pub const types = struct {
11201142
pub const FloatingPointUnit = if (@hasDecl(core, "FloatingPointUnit"))
11211143
core.FloatingPointUnit
11221144
else
1123-
@compileError("this CPU does not have an FPU definition");
1145+
@compileError(
1146+
\\This chip doesn't appear to have an FPU.
1147+
\\
1148+
++ fpu_error_helper_message);
11241149

11251150
/// Nested Vector Interrupt Controller (NVIC).
11261151
pub const NestedVectorInterruptController = core.NestedVectorInterruptController;
@@ -1186,6 +1211,9 @@ pub const types = struct {
11861211
pub const MemoryProtectionUnit = if (@hasDecl(core, "MemoryProtectionUnit"))
11871212
core.MemoryProtectionUnit
11881213
else
1189-
@compileError("this CPU does not have an MPU definition");
1214+
@compileError(
1215+
\\This chip doesn't appear to have an MPU.
1216+
\\
1217+
++ mpu_error_helper_message);
11901218
};
11911219
};

tools/regz/src/atdf.zig

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -121,18 +121,12 @@ fn load_param(ctx: *Context, node: xml.Node, device_id: DeviceID) !void {
121121
"caption",
122122
});
123123

124-
const property_name_map: std.StaticStringMap([]const u8) = .initComptime(.{
125-
.{ "__MPU_PRESENT", "mpu_present" },
126-
.{ "__FPU_PRESENT", "fpu_present" },
127-
.{ "__NVIC_PRIO_BITS", "nvic_prio_bits" },
128-
});
129-
130124
const name = node.get_attribute("name") orelse return error.MissingParamName;
131125
const value = node.get_attribute("value") orelse return error.MissingParamName;
132126
const desc = node.get_attribute("caption");
133127

134128
try db.add_device_property(device_id, .{
135-
.key = property_name_map.get(name) orelse name,
129+
.key = name,
136130
.value = value,
137131
.description = desc,
138132
});

tools/regz/src/embassy.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,7 @@ pub fn load_into_db(db: *Database, path: []const u8) !void {
447447

448448
if (std.mem.indexOf(u8, interrupt.name, "FPU")) |_| {
449449
try db.add_device_property(device_id, .{
450-
.key = "fpu_present",
450+
.key = "cpu.fpuPresent",
451451
.value = "true",
452452
});
453453
}

tools/regz/src/gen.zig

Lines changed: 91 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const EnumID = Database.EnumID;
1414
const StructID = Database.StructID;
1515
const NestedStructField = Database.NestedStructField;
1616

17+
const Properties = @import("properties.zig").Properties;
1718
const Directory = @import("Directory.zig");
1819
const arm = @import("arch/arm.zig");
1920
const avr = @import("arch/avr.zig");
@@ -84,20 +85,26 @@ fn write_device_file(
8485

8586
try write_imports(opts, true, "types.zig", writer);
8687

87-
try writer.writeAll(
88+
try writer.writeAll(@embedFile("properties.zig") ++
89+
\\
8890
\\pub const Interrupt = struct {
8991
\\ name: [:0]const u8,
9092
\\ index: i16,
9193
\\ description: ?[:0]const u8,
9294
\\};
9395
\\
94-
\\
9596
);
9697

97-
const properties = try db.get_device_properties(arena, device.id);
98-
if (properties.len > 0) {
99-
try writer.writeAll("pub const properties = struct {\n");
100-
for (properties) |prop| {
98+
const raw_properties = try db.get_device_properties(arena, device.id);
99+
const properties = process_properties(raw_properties);
100+
101+
try writer.writeAll("\npub const properties: Properties = ");
102+
try std.zon.stringify.serialize(properties, .{}, writer);
103+
try writer.writeAll(";\n");
104+
105+
if (raw_properties.len > 0) {
106+
try writer.writeAll("\npub const raw_properties = struct {\n");
107+
for (raw_properties) |prop| {
101108
try writer.print("pub const {f} = ", .{
102109
std.zig.fmtId(prop.key),
103110
});
@@ -118,7 +125,7 @@ fn write_device_file(
118125
const device_peripherals = try db.get_device_peripherals(arena, device.id);
119126
log.debug("peripheral instances: {}", .{device_peripherals.len});
120127
if (device_peripherals.len > 0) {
121-
try writer.writeAll("pub const peripherals = struct {\n");
128+
try writer.writeAll("\npub const peripherals = struct {\n");
122129
for (device_peripherals) |instance| {
123130
write_device_peripheral(db, arena, &instance, writer) catch |err| {
124131
log.warn("failed to serialize peripheral instance: {}", .{err});
@@ -1285,6 +1292,83 @@ fn to_zero_sentinel(buf: []const u8) [:0]const u8 {
12851292
return buf[0 .. buf.len - 1 :0];
12861293
}
12871294

1295+
fn process_properties(raw_props: []const Database.DeviceProperty) Properties {
1296+
var properties: Properties = .{};
1297+
1298+
for (raw_props) |prop| {
1299+
if (std.mem.eql(u8, prop.key, "cpu.nvicPrioBits") or
1300+
std.mem.eql(u8, prop.key, "__NVIC_PRIO_BITS"))
1301+
{
1302+
if (prop.value) |value| {
1303+
properties.interrupt_priority_bits = std.fmt.parseInt(u8, value, 10) catch blk: {
1304+
log.warn("failed to parse `interrupt_priority_bits` property value: expected integer, got `{s}`", .{value});
1305+
break :blk null;
1306+
};
1307+
} else {
1308+
log.warn("`interrupt_priority_bits` property candidate detected but it has no value", .{});
1309+
}
1310+
}
1311+
1312+
if (std.mem.eql(u8, prop.key, "cpu.vtorPresent") or
1313+
std.mem.eql(u8, prop.key, "__VTOR_PRESENT"))
1314+
{
1315+
if (prop.value) |value| {
1316+
properties.has_vtor = raw_property_value_to_bool(value) catch blk: {
1317+
log.warn("failed to parse `has_vtor` property value: expected boolean, got `{s}`", .{value});
1318+
break :blk null;
1319+
};
1320+
} else {
1321+
log.warn("`has_vtor` property candidate detected but it has no value", .{});
1322+
}
1323+
}
1324+
1325+
if (std.mem.eql(u8, prop.key, "cpu.mpuPresent") or
1326+
std.mem.eql(u8, prop.key, "__MPU_PRESENT"))
1327+
{
1328+
if (prop.value) |value| {
1329+
properties.has_mpu = raw_property_value_to_bool(value) catch blk: {
1330+
log.warn("failed to interpret `has_mpu` property value: expected boolean, got `{s}`", .{value});
1331+
break :blk null;
1332+
};
1333+
} else {
1334+
log.warn("`has_mpu` property candidate detected but it has no value", .{});
1335+
}
1336+
}
1337+
1338+
if (std.mem.eql(u8, prop.key, "cpu.fpuPresent") or
1339+
std.mem.eql(u8, prop.key, "__FPU_PRESENT"))
1340+
{
1341+
if (prop.value) |value| {
1342+
properties.has_fpu = raw_property_value_to_bool(value) catch blk: {
1343+
log.warn("failed to interpret `has_fpu` property value: expected boolean, got `{s}`", .{value});
1344+
break :blk null;
1345+
};
1346+
} else {
1347+
log.warn("`has_fpu` property candidate detected but it has no value", .{});
1348+
}
1349+
}
1350+
}
1351+
1352+
return properties;
1353+
}
1354+
1355+
fn raw_property_value_to_bool(value: []const u8) !bool {
1356+
inline for (&.{ "false", "true" }, 0..) |str, i| {
1357+
if (std.mem.eql(u8, value, str)) {
1358+
return i == 1;
1359+
}
1360+
}
1361+
1362+
inline for (&.{ "0", "1" }, 0..) |str, i| {
1363+
if (std.mem.eql(u8, value, str)) {
1364+
return i == 1;
1365+
}
1366+
}
1367+
1368+
log.warn("failed to interpret `{s}` as bool", .{value});
1369+
return error.BadValue;
1370+
}
1371+
12881372
const tests = @import("output_tests.zig");
12891373

12901374
fn expect_register(expected: *const Register, actual: *const Register) !void {

tools/regz/src/properties.zig

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
pub const Properties = struct {
2+
has_vtor: ?bool = null,
3+
has_mpu: ?bool = null,
4+
has_fpu: ?bool = null,
5+
interrupt_priority_bits: ?u8 = null,
6+
};

tools/regz/src/svd.zig

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -94,12 +94,6 @@ pub fn load_into_db(db: *Database, doc: xml.Doc) !void {
9494
// peripherals
9595
// vendorExtensions
9696

97-
const property_name_map: std.StaticStringMap([]const u8) = .initComptime(.{
98-
.{ "mpuPresent", "mpu_present" },
99-
.{ "fpuPresent", "fpu_present" },
100-
.{ "nvicPrioBits", "nvic_prio_bits" },
101-
});
102-
10397
var cpu_it = root.iterate(&.{}, &.{"cpu"});
10498
if (cpu_it.next()) |cpu| {
10599
const required_properties: []const []const u8 = &.{
@@ -131,7 +125,7 @@ pub fn load_into_db(db: *Database, doc: xml.Doc) !void {
131125
return error.MissingRequiredProperty;
132126
};
133127

134-
const property_name = property_name_map.get(property) orelse try std.mem.join(
128+
const property_name = try std.mem.join(
135129
arena.allocator(),
136130
".",
137131
&.{ "cpu", property },
@@ -144,11 +138,7 @@ pub fn load_into_db(db: *Database, doc: xml.Doc) !void {
144138

145139
for (optional_properties) |property| {
146140
if (cpu.get_value(property)) |value| {
147-
const property_name = property_name_map.get(property) orelse try std.mem.join(
148-
arena.allocator(),
149-
".",
150-
&.{ "cpu", property },
151-
);
141+
const property_name = try std.mem.join(arena.allocator(), ".", &.{ "cpu", property });
152142
try db.add_device_property(device_id, .{
153143
.key = property_name,
154144
.value = value,

0 commit comments

Comments
 (0)