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.

56 lines
1.8 KiB
Zig

const std = @import("std");
const assert = std.debug.assert;
pub fn Mmio(comptime PackedT: type) type {
const size = @bitSizeOf(PackedT);
if ((size % 8) != 0)
@compileError("size must be divisible by 8!");
if (!std.math.isPowerOfTwo(size / 8))
@compileError("size must encode a power of two number of bytes!");
const IntT = std.meta.Int(.unsigned, size);
if (@sizeOf(PackedT) != (size / 8))
@compileError(std.fmt.comptimePrint("IntT and PackedT must have the same size!, they are {} and {} bytes respectively", .{ size / 8, @sizeOf(PackedT) }));
return extern struct {
const Self = @This();
raw: IntT,
pub const underlying_type = PackedT;
pub inline fn read(addr: *volatile Self) PackedT {
return @bitCast(addr.raw);
}
pub inline fn write(addr: *volatile Self, val: PackedT) void {
comptime {
assert(@bitSizeOf(PackedT) == @bitSizeOf(IntT));
}
addr.write_raw(@bitCast(val));
}
pub fn write_raw(addr: *volatile Self, val: IntT) void {
addr.raw = val;
}
pub inline fn modify(addr: *volatile Self, fields: anytype) void {
var val = read(addr);
inline for (@typeInfo(@TypeOf(fields)).Struct.fields) |field| {
@field(val, field.name) = @field(fields, field.name);
}
write(addr, val);
}
pub inline fn toggle(addr: *volatile Self, fields: anytype) void {
var val = read(addr);
inline for (@typeInfo(@TypeOf(fields)).Struct.fields) |field| {
@field(val, @tagName(field.default_value.?)) = !@field(val, @tagName(field.default_value.?));
}
write(addr, val);
}
};
}