-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
destination type 'u32' has size 4 but source type has size 5 #5
Comments
|
Yeah, looks like a bug. |
While debugging the same issue in svd4zig I ended up doing this.This seems to derive from ziglang/zig#2627. Empirically, it seems the problem arises when portions of registers "cross" 16-bit boundaries. Just to be on the safe side, my code splits unused bits on 8-bit boundaries (I only do this on unused portions since I would like to keep everything else as-is). This is not always the case though (see last test below, which crosses the boundary but gets the correct size). Here are some tests based on the example above that try to move around some stuff to see what happens: const assert = @import("std").debug.assert;
pub const fail_orig = packed struct {
cen: packed enum(u1) {
disabled = 0,
enabled = 1,
} = .disabled,
udis: packed enum(u1) {
enabled = 0,
disabled = 1,
} = .enabled,
urs: packed enum(u1) {
any_event = 0,
counter_only = 1,
} = .any_event,
opm: packed enum(u1) {
disabled = 0,
enabled = 1,
} = .disabled,
dir: packed enum(u1) {
up = 0,
down = 1,
} = .up,
cms: packed enum(u2) {
edge_aligned = 0,
center_aligned1 = 1,
center_aligned2 = 2,
center_aligned3 = 3,
} = .edge_aligned,
arpe: packed enum(u1) {
disabled = 0,
enabled = 1,
} = .disabled,
ckd: packed enum(u2) {
div1 = 0,
div2 = 1,
div4 = 2,
} = .div1,
// Initial failing example, this unused piece crosses the 16-bit boundary
// The struct has size 5
_unused10: u22 = 0,
};
pub const ok = packed struct {
cen: packed enum(u1) {
disabled = 0,
enabled = 1,
} = .disabled,
udis: packed enum(u1) {
enabled = 0,
disabled = 1,
} = .enabled,
urs: packed enum(u1) {
any_event = 0,
counter_only = 1,
} = .any_event,
opm: packed enum(u1) {
disabled = 0,
enabled = 1,
} = .disabled,
dir: packed enum(u1) {
up = 0,
down = 1,
} = .up,
cms: packed enum(u2) {
edge_aligned = 0,
center_aligned1 = 1,
center_aligned2 = 2,
center_aligned3 = 3,
} = .edge_aligned,
arpe: packed enum(u1) {
disabled = 0,
enabled = 1,
} = .disabled,
ckd: packed enum(u2) {
div1 = 0,
div2 = 1,
div4 = 2,
} = .div1,
// Splitting this so that it doesn't go over 16-bit boundary
// The struct has size 4
_unused10: u6 = 0,
_unused16: u16 = 0,
};
pub const fail_invert = packed struct {
cen: packed enum(u1) {
disabled = 0,
enabled = 1,
} = .disabled,
udis: packed enum(u1) {
enabled = 0,
disabled = 1,
} = .enabled,
urs: packed enum(u1) {
any_event = 0,
counter_only = 1,
} = .any_event,
opm: packed enum(u1) {
disabled = 0,
enabled = 1,
} = .disabled,
dir: packed enum(u1) {
up = 0,
down = 1,
} = .up,
cms: packed enum(u2) {
edge_aligned = 0,
center_aligned1 = 1,
center_aligned2 = 2,
center_aligned3 = 3,
} = .edge_aligned,
arpe: packed enum(u1) {
disabled = 0,
enabled = 1,
} = .disabled,
ckd: packed enum(u2) {
div1 = 0,
div2 = 1,
div4 = 2,
} = .div1,
// If we invert them, they cross the 16-bit boundary again
// The struct has size 5
_unused16: u16 = 0,
_unused10: u6 = 0,
};
pub const fail_2bit_cross = packed struct {
cen: packed enum(u1) {
disabled = 0,
enabled = 1,
} = .disabled,
udis: packed enum(u1) {
enabled = 0,
disabled = 1,
} = .enabled,
urs: packed enum(u1) {
any_event = 0,
counter_only = 1,
} = .any_event,
opm: packed enum(u1) {
disabled = 0,
enabled = 1,
} = .disabled,
dir: packed enum(u1) {
up = 0,
down = 1,
} = .up,
cms: packed enum(u2) {
edge_aligned = 0,
center_aligned1 = 1,
center_aligned2 = 2,
center_aligned3 = 3,
} = .edge_aligned,
arpe: packed enum(u1) {
disabled = 0,
enabled = 1,
} = .disabled,
ckd: packed enum(u2) {
div1 = 0,
div2 = 1,
div4 = 2,
} = .div1,
_unused10: u5 = 0,
// Here we minimize the crossing part, only these 2 bits (15-16) are crossing
// The struct has size 5
_unused15: u2 = 0,
_unused16: u15 = 0,
};
pub const fail_minimal_cross = packed struct {
_stuff1: u8,
// This crosses the 16-bit boundary
// This struct has size 5
_stuff2: u24,
};
pub const ok_but_cross = packed struct {
_stuff1: u7,
// This crosses the 16-bit boundary too
// But the struct has size 4
_stuff2: u25,
};
test "register size" {
assert(@sizeOf(fail_orig) == 5);
assert(@sizeOf(ok) == 4);
assert(@sizeOf(fail_invert) == 5);
assert(@sizeOf(fail_2bit_cross) == 5);
assert(@sizeOf(fail_minimal_cross) == 5);
assert(@sizeOf(ok_but_cross) == 4);
} |
Thanks for the workaround @rbino |
Yikes. Good research @rbino! Not sure how I want to resolve this --- either impl a workaround in my register generation or wait until it gets fixed upstream. Will leave this open until then. |
When trying to write to a register, I'm getting a size mismatch.
gives the error:
gives 32 and 5.
So I guess it's an alignment issue?
Not sure how to fix.
Here's the definition, just FYI:
The text was updated successfully, but these errors were encountered: