core registers for the m0plus (#26)

* core registers for the m0plus

* do proper optional handling
wch-ch32v003
Matt Knight 2 years ago committed by Matt Knight
parent 6f4850dab7
commit 9af2e274f1

@ -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,9 +860,6 @@ 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);
@ -868,10 +872,14 @@ pub fn toZig(db: *Database, out_writer: anytype) !void {
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) {
@ -889,7 +897,6 @@ pub fn toZig(db: *Database, out_writer: anytype) !void {
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,6 +1307,12 @@ fn genZigRegister(
name,
register.size.?,
base_addr != null,
if (nesting == .namespaced)
if (cluster_offset) |offset|
offset + addr_offset
else
addr_offset
else
addr_offset,
field_range,
"",
@ -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,6 +1352,12 @@ fn genZigRegister(
name,
register.size.?,
base_addr != null,
if (nesting == .namespaced)
if (cluster_offset) |offset|
offset + addr_offset
else
addr_offset
else
addr_offset,
field_range,
"",
@ -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,6 +1418,12 @@ fn genZigRegister(
name,
register.size.?,
base_addr != null,
if (nesting == .namespaced)
if (cluster_offset) |offset|
offset + register.addr_offset
else
register.addr_offset
else
register.addr_offset,
field_range,
array_prefix,
@ -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) = .{},

@ -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)

@ -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(),

@ -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);
}

@ -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 },
});
}

@ -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,
};
}
};

Loading…
Cancel
Save