You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

109 lines
4.1 KiB
Zig

const std = @import("std");
const xml = @import("xml.zig");
const Peripheral = @import("Peripheral.zig");
const Register = @import("Register.zig");
const Field = @import("Field.zig");
const ArenaAllocator = std.heap.ArenaAllocator;
const Allocator = std.mem.Allocator;
pub fn parsePeripheral(arena: *ArenaAllocator, node: *xml.Node) !Peripheral {
const allocator = arena.allocator();
return Peripheral{
.name = try allocator.dupe(u8, xml.getAttribute(node, "name") orelse return error.NoName),
.version = if (xml.getAttribute(node, "version")) |version|
try allocator.dupe(u8, version)
else
null,
.description = if (xml.getAttribute(node, "caption")) |caption|
try allocator.dupe(u8, caption)
else
null,
// TODO: make sure this is always null
.base_addr = null,
};
}
pub fn parseRegister(
arena: *ArenaAllocator,
node: *xml.Node,
register_group_offset: ?usize,
has_fields: bool,
) !Register {
const allocator = arena.allocator();
return Register{
.name = try allocator.dupe(u8, xml.getAttribute(node, "name") orelse return error.NoName),
.description = if (xml.getAttribute(node, "caption")) |caption|
try allocator.dupe(u8, caption)
else
null,
.addr_offset = if (xml.getAttribute(node, "offset")) |reg_offset_str| addr_offset: {
const reg_offset = try std.fmt.parseInt(usize, reg_offset_str, 0);
break :addr_offset if (register_group_offset) |group_offset|
group_offset + reg_offset
else
reg_offset;
} else return error.NoAddrOffset,
.size = if (xml.getAttribute(node, "size")) |size_str| blk: {
const full_size = 8 * try std.fmt.parseInt(usize, size_str, 0);
if (!has_fields) {
const mask = try std.fmt.parseInt(u64, xml.getAttribute(node, "mask") orelse break :blk full_size, 0);
// ensure it starts at bit 0
if (mask & 0x1 == 0)
break :blk full_size;
var cursor: u7 = 0;
while ((mask & (@as(u64, 1) << @intCast(u6, cursor))) != 0 and cursor < @bitSizeOf(u64)) : (cursor += 1) {}
// we now have width, make sure that the mask is contiguous
const width = cursor;
while (cursor < @bitSizeOf(u64)) : (cursor += 1) {
if ((mask & (@as(u64, 1) << @intCast(u6, cursor))) != 0) {
break :blk full_size;
}
} else break :blk width;
}
break :blk full_size;
} else return error.NoSize, // if this shows up then we need to determine the default size of a register
// TODO: ATDF register access
.access = .read_write,
// TODO: ATDF reset_value
.reset_value = null,
// TODO: ATDF reset_mask
.reset_mask = null,
};
}
pub fn parseField(arena: *ArenaAllocator, node: *xml.Node) !Field {
const allocator = arena.allocator();
const name = try allocator.dupe(u8, xml.getAttribute(node, "name") orelse return error.NoName);
const mask = try std.fmt.parseInt(u64, xml.getAttribute(node, "mask") orelse return error.NoMask, 0);
var offset: u7 = 0;
while ((mask & (@as(u64, 1) << @intCast(u6, offset))) == 0 and offset < @bitSizeOf(usize)) : (offset += 1) {}
var cursor: u7 = offset;
while ((mask & (@as(u64, 1) << @intCast(u6, cursor))) != 0 and cursor < @bitSizeOf(u64)) : (cursor += 1) {}
const width = cursor - offset;
while (cursor < @bitSizeOf(u64)) : (cursor += 1)
if ((mask & (@as(u64, 1) << @intCast(u6, cursor))) != 0) {
std.log.warn("found mask with discontinuous bits: {s}, ignoring", .{name});
return error.InvalidMask;
};
return Field{
.name = name,
.description = if (xml.getAttribute(node, "caption")) |caption|
try allocator.dupe(u8, caption)
else
null,
.offset = offset,
.width = width,
// TODO: does atdf have a field level access?
.access = null,
};
}