don't generate system registers (#96)

* don't generate system registers

* handle missing cpu name
wch-ch32v003
Matt Knight 2 years ago
parent c48ca0e86b
commit 7c75bc6297

@ -10,42 +10,52 @@ const gen = @import("../gen.zig");
const InterruptWithIndexAndName = @import("InterruptWithIndexAndName.zig"); const InterruptWithIndexAndName = @import("InterruptWithIndexAndName.zig");
const Interrupt = @import("Interrupt.zig"); const Interrupt = @import("Interrupt.zig");
const svd = @import("../svd.zig");
const log = std.log.scoped(.@"gen.arm"); const log = std.log.scoped(.@"gen.arm");
// it's intended that these interrupts are added to the database in the // it's intended that these interrupts are added to the database in the
// different front-ends. This way this information is serialized for // different front-ends. This way this information is serialized for
// tooling // tooling
pub const system_interrupts = struct {
pub const cortex_m0 = [_]Interrupt{ const system_interrupts = struct {
Interrupt{ .name = "NMI", .index = -14 }, // zig fmt: off
Interrupt{ .name = "HardFault", .index = -13 }, const nmi = Interrupt{ .index = -14, .name = "NMI" };
Interrupt{ .name = "SVCall", .index = -5 }, const hard_fault = Interrupt{ .index = -13, .name = "HardFault" };
Interrupt{ .name = "PendSV", .index = -2 }, const mem_manage = Interrupt{ .index = -12, .name = "MemManageFault" };
}; const bus_fault = Interrupt{ .index = -11, .name = "BusFault" };
const usage_fault = Interrupt{ .index = -10, .name = "UsageFault" };
const secure_fault = Interrupt{ .index = -9, .name = "SecureFault" };
const svcall = Interrupt{ .index = -5, .name = "SVCall" };
const debug_monitor = Interrupt{ .index = -4, .name = "DebugMonitor" };
const pendsv = Interrupt{ .index = -2, .name = "PendSV" };
const systick = Interrupt{ .index = -1, .name = "SysTick" };
// zig fmt: on
pub const cortex_m0 = [_]Interrupt{ nmi, hard_fault, svcall, pendsv };
pub const cortex_m0plus = cortex_m0; pub const cortex_m0plus = cortex_m0;
pub const cortex_m3 = [_]Interrupt{ pub const cortex_m1 = cortex_m0;
Interrupt{ .name = "MemManageFault", .index = -12 }, pub const cortex_m23 = cortex_m0;
Interrupt{ .name = "BusFault", .index = -11 },
Interrupt{ .name = "UsageFault", .index = -10 }, pub const cortex_m3 = [_]Interrupt{ nmi, hard_fault, mem_manage, bus_fault, usage_fault, svcall, pendsv };
Interrupt{ .name = "DebugMonitor", .index = -4 },
} ++ cortex_m0;
pub const cortex_m4 = cortex_m3; pub const cortex_m4 = cortex_m3;
pub const cortex_m7 = cortex_m3;
pub const cortex_m33 = [_]Interrupt{ nmi, hard_fault, mem_manage, bus_fault, usage_fault, secure_fault, svcall, debug_monitor, pendsv };
// The m35p was announced in 2018 and the technical reference manual does
// not list the exceptions. It has been described as an m33 with some
// upgrades, so I'm going give it the same exceptions
pub const cortex_m35p = cortex_m33;
// The m55 was announced in 2020 and I have about the same amount of information as the m35p
pub const cortex_m55 = cortex_m33;
}; };
pub fn load_systick_interrupt(db: *Database, device_id: EntityId) !void {
_ = try db.create_interrupt(device_id, .{
.name = "SysTick",
.index = -1,
// TODO: description
});
}
pub fn load_system_interrupts(db: *Database, device_id: EntityId) !void { pub fn load_system_interrupts(db: *Database, device_id: EntityId) !void {
const arch = db.instances.devices.get(device_id).?.arch; const device = db.instances.devices.get(device_id).?;
assert(arch.is_arm()); assert(device.arch.is_arm());
inline for (@typeInfo(Database.Arch).Enum.fields) |field| { inline for (@typeInfo(Database.Arch).Enum.fields) |field| {
if (arch == @field(Database.Arch, field.name)) { if (device.arch == @field(Database.Arch, field.name)) {
if (@hasDecl(system_interrupts, field.name)) { if (@hasDecl(system_interrupts, field.name)) {
for (@field(system_interrupts, field.name)) |interrupt| { for (@field(system_interrupts, field.name)) |interrupt| {
_ = try db.create_interrupt(device_id, .{ _ = try db.create_interrupt(device_id, .{
@ -59,7 +69,19 @@ pub fn load_system_interrupts(db: *Database, device_id: EntityId) !void {
break; break;
} }
} else { } else {
log.warn("TODO: system interrupts handlers for {}", .{arch}); log.warn("TODO: system interrupts handlers for {}", .{device.arch});
}
const vendor_systick_config = if (device.properties.get("cpu.vendorSystickConfig")) |str|
try svd.parse_bool(str)
else
false;
if (!vendor_systick_config) {
_ = try db.create_interrupt(device_id, .{
.name = system_interrupts.systick.name,
.index = system_interrupts.systick.index,
});
} }
} }
@ -72,25 +94,6 @@ pub fn write_interrupt_vector(
const arch = db.instances.devices.get(device_id).?.arch; const arch = db.instances.devices.get(device_id).?.arch;
assert(arch.is_arm()); assert(arch.is_arm());
switch (arch) {
// the basic vector table below should be fine for cortex-m
.cortex_m0,
.cortex_m0plus,
.cortex_m1,
.cortex_m23,
.cortex_m3,
.cortex_m33,
.cortex_m35p,
.cortex_m4,
.cortex_m55,
.cortex_m7,
=> {},
else => {
log.warn("TODO: exception handlers for {}", .{arch});
return;
},
}
try writer.writeAll( try writer.writeAll(
\\pub const VectorTable = extern struct { \\pub const VectorTable = extern struct {
\\ const Handler = micro.interrupt.Handler; \\ const Handler = micro.interrupt.Handler;
@ -118,10 +121,6 @@ pub fn write_interrupt_vector(
}); });
} }
switch (arch) {
else => log.warn("TODO: exception handlers for {}", .{arch}),
}
std.sort.sort( std.sort.sort(
InterruptWithIndexAndName, InterruptWithIndexAndName,
interrupts.items, interrupts.items,

@ -0,0 +1,159 @@
//! NVIC Registers
//!
//!
//! Offset Register R W Field With Offset Description M0 M0+ M1 M3 M4 M7 M23 M33 M35P M55 ARMV8MBL ARMV8MML SC000 SC3000
//!
//! 0x0000 ISER X X Interrupt Set Enable Register X X X X ? ? ? ? ? ? ? ? ? ?
//! 0x0080 ICER X X Interrupt Clear Enable Register X X X X ? ? ? ? ? ? ? ? ? ?
//! 0x0100 ISPR X X Interrupt Set Pending Register X X X X ? ? ? ? ? ? ? ? ? ?
//! 0x0180 ICPR X X Interrupt Clear Pending Register X X X X ? ? ? ? ? ? ? ? ? ?
//! 0x0200 IABR Interrupt Priority Register 8 ? ? ? ? ? ? ? ? ? ?
//! 0x0300 IP X X 8 8 8 240 ? ? ? ? ? ? ? ? ? ?
//! 0x0E00 STIR X ? ? ? ? ? ? ? ? ? ?
//! INTID 9 0 X ? ? ? ? ? ? ? ? ? ?
//!
const std = @import("std");
const Database = @import("../../Database.zig");
const EntityId = Database.EntityId;
pub const address = 0xe000e100;
// deletes an existing NVIC peripheral if it has one. This is because the
// registers we'll generate are better :)
//
// assumes if the device has interrupts, they've been loaded
pub fn load(db: *Database, device_id: EntityId) !void {
const device = db.instances.devices.get(device_id).?;
if (!device.arch.is_arm())
return;
switch (device.arch) {
.cortex_m0, .cortex_m0plus, .cortex_m1 => {},
else => {
std.log.warn("TODO: implement NVIC register generation for '{}'", .{device.arch});
return;
},
}
const nvic = try db.create_peripheral(.{
.name = "NVIC",
.description = "Nested Vectored Interrupt Controller",
});
_ = try db.create_peripheral_instance(device_id, nvic, .{
.name = "NVIC",
.offset = address,
});
// TODO: behavior is different for cortex-m3/4/7, probably the others too
const interrupt_registers = [_]EntityId{
try db.create_register(nvic, .{ .name = "ISER", .offset = 0x000, .size = 32, .description = "Interrupt Set Enable Register" }),
try db.create_register(nvic, .{ .name = "ICER", .offset = 0x080, .size = 32, .description = "Interrupt Clear Enable Register" }),
try db.create_register(nvic, .{ .name = "ISPR", .offset = 0x100, .size = 32, .description = "Interrupt Set Pending Register" }),
try db.create_register(nvic, .{ .name = "ICPR", .offset = 0x180, .size = 32, .description = "Interrupt Clear Pending Register" }),
};
// TODO: generate IP if any of the above fail, like nvicPrioBits is missing
// interrupt priority registers
if (device.properties.get("cpu.nvicPrioBits")) |bits| if (try std.fmt.parseInt(u32, bits, 10) > 0) {
const ip_addr_offset = 0x300;
var i: u32 = 0;
while (i < 8) : (i += 1) {
const addr_offset = ip_addr_offset + (i * 4);
const reg_name = try std.fmt.allocPrint(db.arena.allocator(), "IP{}", .{i});
_ = try db.create_register(nvic, .{
.name = reg_name,
.description = "Interrupt Priority Register",
.offset = addr_offset,
.size = 32,
});
}
};
// fields for basic registers
const interrupts = db.instances.interrupts;
for (interrupts.keys(), interrupts.values()) |interrupt_id, interrupt_index| {
if (interrupt_index < 0)
continue;
const interrupt_name = db.attrs.name.get(interrupt_id).?;
for (interrupt_registers) |register| {
_ = try db.create_field(register, .{
.name = interrupt_name,
.offset = @bitCast(u32, interrupt_index),
.size = 1,
});
}
const nvic_prio_bits = try std.fmt.parseInt(
u32,
device.properties.get("cpu.nvicPrioBits") orelse return error.MissingNvicPrioBits,
10,
);
if (nvic_prio_bits == 0) continue;
const reg_name = try std.fmt.allocPrint(db.arena.allocator(), "IP{}", .{interrupt_index >> 2});
const reg_id = try db.get_entity_id_by_name("type.register", reg_name);
_ = try db.create_field(reg_id, .{
.name = interrupt_name,
.offset = (8 * (@intCast(u8, interrupt_index) % 4)) + (8 - nvic_prio_bits),
.size = nvic_prio_bits,
});
}
// TODO: cpu module specific NVIC registers
// destroy registers that line up with NVIC registers
var unique_peripherals = std.ArrayList(EntityId).init(db.gpa);
defer unique_peripherals.deinit();
for (db.types.peripherals.keys()) |peripheral_id| outer: {
var unique_instance_id: ?EntityId = null;
const instances = db.instances.peripherals;
for (instances.keys(), instances.values()) |instance_id, type_id| {
if (type_id == peripheral_id) {
if (type_id == nvic)
break :outer;
if (unique_instance_id == null) {
unique_instance_id = instance_id;
} else break :outer;
}
}
// every peripheral type should have an instance
try unique_peripherals.append(unique_instance_id.?);
}
// Put together a hit list of register addresses
var hit_list = std.AutoArrayHashMap(u64, void).init(db.gpa);
defer hit_list.deinit();
for (db.children.registers.get(nvic).?.keys()) |child_id| {
if (db.attrs.offset.get(child_id)) |register_offset| {
std.log.debug("hit_list entry: 0x{x}", .{address + register_offset});
try hit_list.put(address + register_offset, {});
}
}
var destroy_list = std.AutoArrayHashMap(EntityId, void).init(db.gpa);
defer destroy_list.deinit();
for (unique_peripherals.items) |instance_id| {
const peripheral_id = db.instances.peripherals.get(instance_id).?;
const instance_offset = db.attrs.offset.get(instance_id).?;
const children = db.children.registers.get(peripheral_id) orelse continue;
for (children.keys()) |register_id| {
const register_offset = db.attrs.offset.get(register_id) orelse continue;
if (hit_list.contains(instance_offset + register_offset))
try destroy_list.put(register_id, {});
}
}
for (destroy_list.keys()) |register_id|
db.destroy_entity(register_id);
}

@ -5,7 +5,6 @@ const assert = std.debug.assert;
const xml = @import("xml.zig"); const xml = @import("xml.zig");
const arm = @import("arch/arm.zig"); const arm = @import("arch/arm.zig");
const cmsis = @import("svd/cmsis.zig");
const Database = @import("Database.zig"); const Database = @import("Database.zig");
const EntityId = Database.EntityId; const EntityId = Database.EntityId;
@ -52,6 +51,10 @@ const svd_boolean = std.ComptimeStringMap(bool, .{
.{ "0", false }, .{ "0", false },
}); });
pub fn parse_bool(str: []const u8) !bool {
return svd_boolean.get(str) orelse error.InvalidSvdBoolean;
}
pub fn load_into_db(db: *Database, doc: xml.Doc) !void { pub fn load_into_db(db: *Database, doc: xml.Doc) !void {
const root = try doc.get_root_element(); const root = try doc.get_root_element();
@ -83,75 +86,50 @@ pub fn load_into_db(db: *Database, doc: xml.Doc) !void {
var cpu_it = root.iterate(&.{}, "cpu"); var cpu_it = root.iterate(&.{}, "cpu");
if (cpu_it.next()) |cpu| { if (cpu_it.next()) |cpu| {
const cpu_name = cpu.get_value("name") orelse return error.MissingCpuName; const required_properties: []const []const u8 = &.{
const cpu_revision = cpu.get_value("revision") orelse return error.MissingCpuRevision; "name",
const nvic_prio_bits = cpu.get_value("nvicPrioBits") orelse return error.MissingNvicPrioBits; "revision",
const vendor_systick_config = cpu.get_value("vendorSystickConfig") orelse return error.MissingVendorSystickConfig; "endian",
"nvicPrioBits",
const arch = arch_from_str(cpu_name); };
db.instances.devices.getEntry(device_id).?.value_ptr.arch = arch;
if (arch.is_arm())
try arm.load_system_interrupts(db, device_id);
// TODO: is this the right logic?
if (svd_boolean.get(vendor_systick_config)) |systick| {
if (!systick)
try arm.load_systick_interrupt(db, device_id);
} else {
try arm.load_systick_interrupt(db, device_id);
}
// TODO:
// cpu name => arch
try db.add_device_property(device_id, "cpu.name", cpu_name);
try db.add_device_property(device_id, "cpu.revision", cpu_revision);
try db.add_device_property(device_id, "cpu.nvic_prio_bits", nvic_prio_bits);
try db.add_device_property(device_id, "cpu.vendor_systick_config", vendor_systick_config);
if (cpu.get_value("endian")) |endian|
try db.add_device_property(device_id, "cpu.endian", endian);
if (cpu.get_value("mpuPresent")) |mpu|
try db.add_device_property(device_id, "cpu.mpu", mpu);
if (cpu.get_value("fpuPresent")) |fpu|
try db.add_device_property(device_id, "cpu.fpu", fpu);
if (cpu.get_value("dspPresent")) |dsp|
try db.add_device_property(device_id, "cpu.dsp", dsp);
if (cpu.get_value("icachePresent")) |icache|
try db.add_device_property(device_id, "cpu.icache", icache);
if (cpu.get_value("dcachePresent")) |dcache|
try db.add_device_property(device_id, "cpu.dcache", dcache);
if (cpu.get_value("itcmPresent")) |itcm|
try db.add_device_property(device_id, "cpu.itcm", itcm);
if (cpu.get_value("dtcmPresent")) |dtcm| const optional_properties: []const []const u8 = &.{
try db.add_device_property(device_id, "cpu.dtcm", dtcm); "vendorSystickConfig",
"mpuPresent",
"fpuPresent",
"dspPresent",
"icachePresent",
"dcachePresent",
"itcmPresent",
"dtcmPresent",
"vtorPresent",
"deviceNumInterrupts",
"fpuDP",
"sauNumRegions",
"sauRegionsConfig",
};
if (cpu.get_value("vtorPresent")) |vtor| for (required_properties) |property| {
try db.add_device_property(device_id, "cpu.vtor", vtor); const value = cpu.get_value(property) orelse {
std.log.err("missing cpu property: {s}", .{property});
return error.MissingRequiredProperty;
};
if (cpu.get_value("deviceNumInterrupts")) |num_interrupts| const property_name = try std.mem.join(db.arena.allocator(), ".", &.{ "cpu", property });
try db.add_device_property(device_id, "cpu.num_interrupts", num_interrupts); try db.add_device_property(device_id, property_name, value);
}
// fpuDP for (optional_properties) |property| {
// sauNumRegions if (cpu.get_value(property)) |value| {
// sauRegionsConfig const property_name = try std.mem.join(db.arena.allocator(), ".", &.{ "cpu", property });
try db.add_device_property(device_id, property_name, value);
}
}
} }
if (cpu_it.next() != null) if (cpu_it.next() != null)
log.warn("there are multiple CPUs", .{}); log.warn("there are multiple CPUs", .{});
if (db.instances.devices.getEntry(device_id)) |device| {
const arch = device.value_ptr.arch;
if (arch.is_arm()) try cmsis.add_core_registers(db, arch, device_id);
}
var ctx = Context{ var ctx = Context{
.db = db, .db = db,
}; };
@ -175,10 +153,13 @@ pub fn load_into_db(db: *Database, doc: xml.Doc) !void {
}; };
} }
if (db.instances.devices.getEntry(device_id)) |device| { const device = db.instances.devices.getEntry(device_id).?.value_ptr;
const arch = device.value_ptr.arch; device.arch = if (device.properties.get("cpu.name")) |cpu_name|
if (arch.is_arm()) try cmsis.add_nvic_fields(db, arch, device_id); arch_from_str(cpu_name)
} else
.unknown;
if (device.arch.is_arm())
try arm.load_system_interrupts(db, device_id);
db.assert_valid(); db.assert_valid();
} }

@ -1,99 +0,0 @@
const std = @import("std");
const svd = @import("../svd.zig");
const Database = @import("../Database.zig");
const EntityId = Database.EntityId;
const cores = struct {
const cortex_m0 = @import("cmsis/cortex_m0.zig");
const cortex_m0plus = @import("cmsis/cortex_m0plus.zig");
const cortex_m1 = @import("cmsis/cortex_m1.zig");
};
fn add_systick_registers(db: *Database, device_id: EntityId, scs_id: EntityId) !void {
const systick_type = try db.create_register_group(scs_id, .{
.name = "SysTick",
.description = "System Tick Timer",
});
_ = try db.create_peripheral_instance(device_id, systick_type, .{
.name = "SysTick",
.offset = 0xe000e010,
});
const ctrl_id = try db.create_register(systick_type, .{
.name = "CTRL",
.description = "SysTick Control and Status Register",
.offset = 0x0,
.size = 32,
});
const load_id = try db.create_register(systick_type, .{
.name = "LOAD",
.description = "SysTick Reload Value Register",
.offset = 0x4,
.size = 32,
});
const val_id = try db.create_register(systick_type, .{
.name = "VAL",
.description = "SysTick Current Value Register",
.offset = 0x8,
.size = 32,
});
const calib_id = try db.create_register(systick_type, .{
.name = "CALIB",
.description = "SysTick Calibration Register",
.offset = 0xc,
.size = 32,
.access = .read_only,
});
// CTRL fields
_ = try db.create_field(ctrl_id, .{ .name = "ENABLE", .offset = 0, .size = 1 });
_ = try db.create_field(ctrl_id, .{ .name = "TICKINT", .offset = 1, .size = 1 });
_ = try db.create_field(ctrl_id, .{ .name = "CLKSOURCE", .offset = 2, .size = 1 });
_ = try db.create_field(ctrl_id, .{ .name = "COUNTFLAG", .offset = 16, .size = 1 });
// LOAD fields
_ = try db.create_field(load_id, .{ .name = "RELOAD", .offset = 0, .size = 24 });
// VAL fields
_ = try db.create_field(val_id, .{ .name = "CURRENT", .offset = 0, .size = 24 });
// CALIB fields
_ = try db.create_field(calib_id, .{ .name = "TENMS", .offset = 0, .size = 24 });
_ = try db.create_field(calib_id, .{ .name = "SKEW", .offset = 30, .size = 1 });
_ = try db.create_field(calib_id, .{ .name = "NOREF", .offset = 31, .size = 1 });
}
pub fn add_core_registers(db: *Database, cpu_name: Database.Arch, device_id: EntityId) !void {
const type_id = try db.create_peripheral(.{
.name = "SCS",
.description = "System Control Space",
});
if (db.instances.devices.get(device_id)) |cpu| {
if (!(try has_vendor_systick_config(cpu)))
try add_systick_registers(db, device_id, type_id);
inline for (@typeInfo(cores).Struct.decls) |decl|
if (cpu_name == @field(Database.Arch, decl.name))
try @field(cores, decl.name).add_core_registers(db, device_id, type_id);
}
}
pub fn add_nvic_fields(db: *Database, cpu_name: Database.Arch, device_id: EntityId) !void {
inline for (@typeInfo(cores).Struct.decls) |decl|
if (cpu_name == @field(Database.Arch, decl.name))
try @field(cores, decl.name).add_nvic_fields(db, device_id);
}
fn has_vendor_systick_config(cpu: anytype) !bool {
if (cpu.properties.get("cpu.vendor_systick_config")) |systick| {
if (std.mem.eql(u8, systick, "false") or std.mem.eql(u8, systick, "0")) {
return false;
} else if (std.mem.eql(u8, systick, "true") or std.mem.eql(u8, systick, "1")) {
return true;
} else {
return error.BadVendorSystickConfigRepresentation;
}
}
return error.MissingVendorSystickConfig;
}

@ -1,199 +0,0 @@
const std = @import("std");
const Database = @import("../../Database.zig");
const EntityId = Database.EntityId;
const parseInt = std.fmt.parseInt;
pub fn add_core_registers(db: *Database, device_id: EntityId, scs_id: EntityId) !void {
try add_nvic_cluster(db, device_id, scs_id);
try add_scb_cluster(db, device_id, scs_id);
}
pub fn add_nvic_cluster(db: *Database, device_id: EntityId, scs_id: EntityId) !void {
const nvic = try db.create_register_group(scs_id, .{
.name = "NVIC",
.description = "Nested Vectored Interrupt Controller",
});
_ = try db.create_peripheral_instance(device_id, scs_id, .{
.name = "NVIC",
.offset = 0xe000e100,
});
_ = try db.create_register(nvic, .{
.name = "ISER",
.description = "Interrupt Set Enable Register",
.offset = 0x000,
.size = 32,
});
_ = try db.create_register(nvic, .{
.name = "ICER",
.description = "Interrupt Clear Enable Register",
.offset = 0x080,
.size = 32,
});
_ = try db.create_register(nvic, .{
.name = "ISPR",
.description = "Interrupt Set Pending Register",
.offset = 0x100,
.size = 32,
});
_ = try db.create_register(nvic, .{
.name = "ICPR",
.description = "Interrupt Clear Pending Register",
.offset = 0x180,
.size = 32,
});
// interrupt priority registers
if (db.instances.devices.get(device_id)) |cpu|
if (cpu.properties.get("cpu.nvic_prio_bits")) |bits| if (try parseInt(u32, bits, 10) > 0) {
const ip_addr_offset = 0x300;
var i: u32 = 0;
while (i < 8) : (i += 1) {
const addr_offset = ip_addr_offset + (i * 4);
const reg_name = try std.fmt.allocPrint(db.arena.allocator(), "IPR{}", .{i});
_ = try db.create_register(nvic, .{
.name = reg_name,
.description = "Interrupt Priority Register",
.offset = addr_offset,
.size = 32,
});
}
};
}
pub fn add_nvic_fields(db: *Database, device_id: EntityId) !void {
const interrupt_registers: [4]EntityId = .{
try db.get_entity_id_by_name("type.register", "ISER"),
try db.get_entity_id_by_name("type.register", "ICER"),
try db.get_entity_id_by_name("type.register", "ISPR"),
try db.get_entity_id_by_name("type.register", "ICPR"),
};
var interrupt_iter = db.instances.interrupts.iterator();
while (interrupt_iter.next()) |interrupt_kv| {
if (interrupt_kv.value_ptr.* < 0) continue;
const interrupt_name = db.attrs.name.get(interrupt_kv.key_ptr.*).?;
const interrupt_index = @bitCast(u32, interrupt_kv.value_ptr.*);
for (interrupt_registers) |register| {
_ = try db.create_field(register, .{
.name = interrupt_name,
.offset = interrupt_index,
.size = 1,
});
}
const nvic_prio_bits = try parseInt(
u32,
db.instances.devices.get(device_id).?.properties.get("cpu.nvic_prio_bits") orelse return error.MissingNvicPrioBits,
10,
);
if (nvic_prio_bits == 0) continue;
const reg_name = try std.fmt.allocPrint(db.arena.allocator(), "IPR{}", .{interrupt_index >> 2});
const reg_id = try db.get_entity_id_by_name("type.register", reg_name);
_ = try db.create_field(reg_id, .{
.name = interrupt_name,
.offset = (8 * (@intCast(u8, interrupt_index) % 4)) + (8 - nvic_prio_bits),
.size = nvic_prio_bits,
});
}
}
pub fn add_scb_cluster(db: *Database, device_id: EntityId, scs_id: EntityId) !void {
const scb = try db.create_register_group(scs_id, .{
.name = "SCB",
.description = "System Control Block",
});
_ = try db.create_peripheral_instance(device_id, scs_id, .{
.name = "SCB",
.offset = 0xe000ed00,
});
const cpuid = try db.create_register(scb, .{
.name = "CPUID",
.offset = 0x000,
.access = .read_only,
.size = 32,
});
const icsr = try db.create_register(scb, .{
.name = "ICSR",
.description = "Interrupt Control and State Register",
.offset = 0x004,
.size = 32,
});
const aircr = try db.create_register(scb, .{
.name = "AIRCR",
.description = "Application Interrupt and Reset Control Register",
.offset = 0x00c,
.size = 32,
});
const scr = try db.create_register(scb, .{
.name = "SCR",
.description = "System Control Register",
.offset = 0x010,
.size = 32,
});
const ccr = try db.create_register(scb, .{
.name = "CCR",
.description = "Configuration Control Register",
.offset = 0x014,
.size = 32,
});
const shp = try db.create_register(scb, .{
.name = "SHP",
.description = "System Handlers Priority Registers. [0] is RESERVED",
.offset = 0x01c,
.size = 32,
//.dimension = .{
// .dim = 2,
//},
});
_ = shp;
const shcsr = try db.create_register(scb, .{
.name = "SHCSR",
.description = "System Handler Control and State Register",
.offset = 0x024,
.size = 32,
});
// CPUID fields
_ = try db.create_field(cpuid, .{ .name = "REVISION", .offset = 0, .size = 4 });
_ = try db.create_field(cpuid, .{ .name = "PARTNO", .offset = 4, .size = 12 });
_ = try db.create_field(cpuid, .{ .name = "ARCHITECTURE", .offset = 16, .size = 4 });
_ = try db.create_field(cpuid, .{ .name = "VARIANT", .offset = 20, .size = 4 });
_ = try db.create_field(cpuid, .{ .name = "IMPLEMENTER", .offset = 24, .size = 8 });
// ICSR fields
_ = try db.create_field(icsr, .{ .name = "VECTACTIVE", .offset = 0, .size = 9 });
_ = try db.create_field(icsr, .{ .name = "VECTPENDING", .offset = 12, .size = 9 });
_ = try db.create_field(icsr, .{ .name = "ISRPENDING", .offset = 22, .size = 1 });
_ = try db.create_field(icsr, .{ .name = "ISRPREEMPT", .offset = 23, .size = 1 });
_ = try db.create_field(icsr, .{ .name = "PENDSTCLR", .offset = 25, .size = 1 });
_ = try db.create_field(icsr, .{ .name = "PENDSTSET", .offset = 26, .size = 1 });
_ = try db.create_field(icsr, .{ .name = "PENDSVCLR", .offset = 27, .size = 1 });
_ = try db.create_field(icsr, .{ .name = "PENDSVSET", .offset = 28, .size = 1 });
_ = try db.create_field(icsr, .{ .name = "NMIPENDSET", .offset = 31, .size = 1 });
// AIRCR fields
_ = try db.create_field(aircr, .{ .name = "VECTCLRACTIVE", .offset = 1, .size = 1 });
_ = try db.create_field(aircr, .{ .name = "SYSRESETREQ", .offset = 2, .size = 1 });
_ = try db.create_field(aircr, .{ .name = "ENDIANESS", .offset = 15, .size = 1 });
_ = try db.create_field(aircr, .{ .name = "VECTKEY", .offset = 16, .size = 16 });
// SCR fields
_ = try db.create_field(scr, .{ .name = "SLEEPONEXIT", .offset = 1, .size = 1 });
_ = try db.create_field(scr, .{ .name = "SLEEPDEEP", .offset = 2, .size = 1 });
_ = try db.create_field(scr, .{ .name = "SEVONPEND", .offset = 4, .size = 1 });
// CCR fields
_ = try db.create_field(ccr, .{ .name = "UNALIGN_TRP", .offset = 3, .size = 1 });
_ = try db.create_field(ccr, .{ .name = "STKALIGN", .offset = 9, .size = 1 });
// SHCSR fields
_ = try db.create_field(shcsr, .{ .name = "SVCALLPENDED", .offset = 15, .size = 1 });
}

@ -1,187 +0,0 @@
const std = @import("std");
const Database = @import("../../Database.zig");
const EntityId = Database.EntityId;
const cortex_m0 = @import("cortex_m0.zig");
pub const add_nvic_fields = cortex_m0.add_nvic_fields;
pub fn add_core_registers(db: *Database, device_id: EntityId, scs: EntityId) !void {
const scb = try db.create_register_group(scs, .{
.name = "SCB",
.description = "System Control Block",
});
_ = try db.create_peripheral_instance(device_id, scs, .{
.name = "SCB",
.offset = 0xe000ed00,
});
const cpuid = try db.create_register(scb, .{
.name = "CPUID",
.offset = 0x000,
.access = .read_only,
.size = 32,
});
const icsr = try db.create_register(scb, .{
.name = "ICSR",
.description = "Interrupt Control and State Register",
.offset = 0x004,
.size = 32,
});
const aircr = try db.create_register(scb, .{
.name = "AIRCR",
.description = "Application Interrupt and Reset Control Register",
.offset = 0x00c,
.size = 32,
});
const scr = try db.create_register(scb, .{
.name = "SCR",
.description = "System Control Register",
.offset = 0x010,
.size = 32,
});
const ccr = try db.create_register(scb, .{
.name = "CCR",
.description = "Configuration Control Register",
.offset = 0x014,
.size = 32,
});
const shp = try db.create_register(scb, .{
.name = "SHP",
.description = "System Handlers Priority Registers. [0] is RESERVED",
.offset = 0x01c,
.size = 32,
//.dimension = .{
// .dim = 2,
//},
});
_ = shp;
const shcsr = try db.create_register(scb, .{
.name = "SHCSR",
.description = "System Handler Control and State Register",
.offset = 0x024,
.size = 32,
});
if (db.instances.devices.get(device_id)) |cpu| if (cpu.properties.get("cpu.vtor") != null) {
const vtor = try db.create_register(scb, .{
.name = "VTOR",
.description = "Vector Table Offset Register",
.offset = 0x08,
.size = 32,
});
_ = try db.create_field(vtor, .{
.name = "TBLOFF",
.offset = 8,
.size = 24,
});
};
// CPUID fields
_ = try db.create_field(cpuid, .{ .name = "REVISION", .offset = 0, .size = 4 });
_ = try db.create_field(cpuid, .{ .name = "PARTNO", .offset = 4, .size = 12 });
_ = try db.create_field(cpuid, .{ .name = "ARCHITECTURE", .offset = 16, .size = 4 });
_ = try db.create_field(cpuid, .{ .name = "VARIANT", .offset = 20, .size = 4 });
_ = try db.create_field(cpuid, .{ .name = "IMPLEMENTER", .offset = 24, .size = 8 });
// ICSR fields
_ = try db.create_field(icsr, .{ .name = "VECTACTIVE", .offset = 0, .size = 9 });
_ = try db.create_field(icsr, .{ .name = "VECTPENDING", .offset = 12, .size = 9 });
_ = try db.create_field(icsr, .{ .name = "ISRPENDING", .offset = 22, .size = 1 });
_ = try db.create_field(icsr, .{ .name = "ISRPREEMPT", .offset = 23, .size = 1 });
_ = try db.create_field(icsr, .{ .name = "PENDSTCLR", .offset = 25, .size = 1 });
_ = try db.create_field(icsr, .{ .name = "PENDSTSET", .offset = 26, .size = 1 });
_ = try db.create_field(icsr, .{ .name = "PENDSVCLR", .offset = 27, .size = 1 });
_ = try db.create_field(icsr, .{ .name = "PENDSVSET", .offset = 28, .size = 1 });
_ = try db.create_field(icsr, .{ .name = "NMIPENDSET", .offset = 31, .size = 1 });
// AIRCR fields
_ = try db.create_field(aircr, .{ .name = "VECTCLRACTIVE", .offset = 1, .size = 1 });
_ = try db.create_field(aircr, .{ .name = "SYSRESETREQ", .offset = 2, .size = 1 });
_ = try db.create_field(aircr, .{ .name = "ENDIANESS", .offset = 15, .size = 1 });
_ = try db.create_field(aircr, .{ .name = "VECTKEY", .offset = 16, .size = 16 });
// SCR fields
_ = try db.create_field(scr, .{ .name = "SLEEPONEXIT", .offset = 1, .size = 1 });
_ = try db.create_field(scr, .{ .name = "SLEEPDEEP", .offset = 2, .size = 1 });
_ = try db.create_field(scr, .{ .name = "SEVONPEND", .offset = 4, .size = 1 });
// CCR fields
_ = try db.create_field(ccr, .{ .name = "UNALIGN_TRP", .offset = 3, .size = 1 });
_ = try db.create_field(ccr, .{ .name = "STKALIGN", .offset = 9, .size = 1 });
// SHCSR fields
_ = try db.create_field(shcsr, .{ .name = "SVCALLPENDED", .offset = 15, .size = 1 });
try cortex_m0.add_nvic_cluster(db, device_id, scs);
if (db.instances.devices.get(device_id)) |cpu| if (cpu.properties.get("cpu.mpu") != null)
try add_mpu_registers(db, device_id, scs);
}
fn add_mpu_registers(db: *Database, device_id: EntityId, scs: EntityId) !void {
const mpu = try db.create_register_group(scs, .{
.name = "MPU",
.description = "Memory Protection Unit",
});
_ = try db.create_peripheral_instance(device_id, scs, .{
.name = "MPU",
.offset = 0xd90,
});
const type_reg = try db.create_register(mpu, .{
.name = "TYPE",
.description = "MPU Type Register",
.offset = 0x00,
.access = .read_only,
.size = 32,
});
const ctrl = try db.create_register(mpu, .{
.name = "CTRL",
.description = "MPU Control Register",
.offset = 0x04,
.size = 32,
});
const rnr = try db.create_register(mpu, .{
.name = "RNR",
.description = "MPU Region RNRber Register",
.offset = 0x08,
.size = 32,
});
const rbar = try db.create_register(mpu, .{
.name = "RBAR",
.description = "MPU Region Base Address Register",
.offset = 0x0c,
.size = 32,
});
const rasr = try db.create_register(mpu, .{
.name = "RASR",
.description = "MPU Region Attribute and Size Register",
.offset = 0x10,
.size = 32,
});
_ = try db.create_field(type_reg, .{ .name = "SEPARATE", .offset = 0, .size = 1 });
_ = try db.create_field(type_reg, .{ .name = "DREGION", .offset = 8, .size = 8 });
_ = try db.create_field(type_reg, .{ .name = "IREGION", .offset = 16, .size = 8 });
_ = try db.create_field(ctrl, .{ .name = "ENABLE", .offset = 0, .size = 1 });
_ = try db.create_field(ctrl, .{ .name = "HFNMIENA", .offset = 1, .size = 1 });
_ = try db.create_field(ctrl, .{ .name = "PRIVDEFENA", .offset = 2, .size = 1 });
_ = try db.create_field(rnr, .{ .name = "REGION", .offset = 0, .size = 8 });
_ = try db.create_field(rbar, .{ .name = "REGION", .offset = 0, .size = 4 });
_ = try db.create_field(rbar, .{ .name = "VALID", .offset = 4, .size = 1 });
_ = try db.create_field(rbar, .{ .name = "ADDR", .offset = 8, .size = 24 });
_ = try db.create_field(rasr, .{ .name = "ENABLE", .offset = 0, .size = 1 });
_ = try db.create_field(rasr, .{ .name = "SIZE", .offset = 1, .size = 5 });
_ = try db.create_field(rasr, .{ .name = "SRD", .offset = 8, .size = 8 });
_ = try db.create_field(rasr, .{ .name = "B", .offset = 16, .size = 1 });
_ = try db.create_field(rasr, .{ .name = "C", .offset = 17, .size = 1 });
_ = try db.create_field(rasr, .{ .name = "S", .offset = 18, .size = 1 });
_ = try db.create_field(rasr, .{ .name = "TEX", .offset = 19, .size = 3 });
_ = try db.create_field(rasr, .{ .name = "AP", .offset = 24, .size = 3 });
_ = try db.create_field(rasr, .{ .name = "XN", .offset = 28, .size = 1 });
}

@ -1,30 +0,0 @@
const std = @import("std");
const Database = @import("../../Database.zig");
const EntityId = Database.EntityId;
const cortex_m0 = @import("cortex_m0.zig");
pub const add_nvic_fields = cortex_m0.add_nvic_fields;
pub fn add_core_registers(db: *Database, device_id: EntityId, scs_id: EntityId) !void {
try cortex_m0.add_nvic_cluster(db, device_id, scs_id);
try cortex_m0.add_scb_cluster(db, device_id, scs_id);
const scnscb = try db.create_register_group(scs_id, .{
.name = "SCnSCN",
.description = "System Control and ID Register not in the SCB",
});
_ = try db.create_peripheral_instance(device_id, scnscb, .{
.name = "SCnSCB",
.offset = 0x0,
});
const actlr = try db.create_register(scnscb, .{
.name = "ACTLR",
.description = "Auxilary Control Register",
.offset = 0x8,
.size = 32,
});
_ = try db.create_field(actlr, .{ .name = "ITCMLAEN", .offset = 3, .size = 1 });
_ = try db.create_field(actlr, .{ .name = "ITCMUAEN", .offset = 4, .size = 1 });
}
Loading…
Cancel
Save