Good news, I got a serial cable for my Zig PinePhone project, so finally I can debug without relying on the color of an LED
So I put together this code to debug some 32bit register addresses & values, and a few surprises caught me out along the way:
for(0ā¦7) limited to usize, and forwards only ?
u5 errors with >>
the number of truncate sprinkles I needed
I ambitiously started with this:
for (0..8) |i| {
const nibble = (v >> ((7 - i) * 4)) & 0xF;
...
}
What I ended up with feels very noisy, and not sure if it is correct? since I dont understand the u5 requirement. But further than I got using while(), and at least it seems to work!
A u5 represents values between 0-31, which is the number different shifts to the right or left you can do before a u32 is shifted out. If you use a u64 the shifter argument (?) must be a u6 or smaller.
(Iāve replaced your log functions with std.debug.print, just for my own convenience when I gave this a quick test)
In particular, your @truncates are slightly odd/not-best-practice ā they tell the compiler to throw away any data āaboveā the truncate. Contrast: the @intCast in const shift: u5 = @intCast((7 - i) * 4); instead tells the compiler āthis is purely a type change, this operation wonāt lose any dataā and then the compiler will holler if you were wrong about that, which is nice. (you might consider a while loop instead ā youāre correct that for-loops are usize-only, and only increasing)
Your code works as-is, but the nuances of the different conversion builtins lets the compiler help you out more in case you made a bad assumption, or the code changes later, etc. The point of the verbosity is to squash bugs.
Itās a bit of a headache and itās pedantic for sure, but it fits zig zen:
Thanks for a detailed and informative first post It feels like the intCast there should be interchangable with as(u5) - complains type usize. And that the truncate shouldnt be required - complains expected u4.
So we still end up with 3 magic spells compared to the āCā code. Something that looks like the compiler should be able to determine is all in range since i is only 0ā¦8. And anyway I dont see the harm in >> with a larger type/value.
Iāll get my head around it eventually, just feels a bit like casting random spells until I find the magic combination. Thanks again for the help.
I think the difference is that @as runs at comptime(*), but @intCast runs at runtime. So, writing @as(u4, my_u8_var) is a compile error, because the type u8 might hold numbers that the type u4 canāt hold. But var x: u4 = @intCast(my_u8_var) compiles fine ā this might error at runtime if my_u8_var happens to be e.g. 200, but youāre telling the compiler āI claim my_u8_var will always fit into a u4, but please crash at runtime if Iām wrongā(**)
truncate shouldnt be required
no, itās required! (in my version) I didnāt write &0xF anywhere. Iām relying on @truncate to do that truncation for me, along with changing the type. (It would be great if the compiler could figure out that @as(u4, x&0xF) is valid ā thatās one of the things that seems like it might change in the future)
(*)ā@as runs at comptimeā - Iām unsure if this is technically true, someone who knows more please chime in! but it seems true when casting numbers
(**)but note this will not crash in ReleaseFast ā see the manual on Illegal Behavior)
feels a bit like casting random spells until I find the magic combination
yup, I feel that. I got through it by looking at the docs again and again and again and again⦠and eventually I learned, somehow