Hello everyone !
I’m currently working on a RiscV emulator as part of a larger project. I have managed to implement a (maybe) working RV32I core, and while doing so I encountered some friction while wokring with value that need to be treates as signed integers or unsigned depending on the context.
The RV32I uses 32 32-bit registers in its CPU. So at first I modeled them as a [32]u32
array. But sometimes operations need to treat the values as signed instead of unsigned. So you start do write many casting operations similar to this
(untested zig pseudo-code bellow, also not a real riscv instruction)
// getImmediate returns a u32
const immediate_value : i32 = @bitCast(getImmediate(current_instruction));
const target_register = getTargetRegister(current_instruction);
const register_value = @bitCast(cpu.registers[target_register]);
cpu.registers[target_register] = @bitCast(register_value +% immediate_value);
It’s kinda okay, but pretty verbose, and can get even worse when you need to do bit operations on these value, especially if you need to add @as in the mix if you are in the middle of an expression and the destination type is not known.
The problem was also encountered by @floooh in their blog post about (also) implementing emulators in zig (section Bit Twiddling and Integer Math can be awkward)
Now think I have found out a pretty good workflow to make this kind of code simpler : use a packed union with both the signed and unsigned value as its members, and use those to get the proper signed or unsigned value as needed :
const Value = packed union {
u: u32,
i: i32,
};
Now the previous code can be written as
const target_register = getTargetRegister(current_instruction);
// now getImmediate returns a `Value`
cpu.registers[target_register].i = cpu.registers[target_register].i +% getImmediate(current_instruction).i
which in my opinion is far cleaner while still being type-safe.
You can find the code for my emulator here (no online git yet as it’s very WIP). The code for decoding and executing instructions starts at line 176. Feel free to review other parts of the code if you want !
Thanks for reading !