Calculating dynamic bitmasks for function generation?

So, I'm writing a disassembler/assembler library for the RISC-V architecture (mainly as an experiment but I'm hoping to at some point merge this with an already existing project). RISC-V uses masks to determine instructions and to determine the opcodes to generate. For example, the ADD instruction sets bits 25..32 and 12..15 to 0, 2..7 to 0Ch, and 0..2 to 3. What I'm wondering about is the part that isn't static: the operands themselves. The ADD instruction takes a destination register (RD, bits 7 .. 12) and two source registers (RS1 and RS2, bits 15..20 and 20..25). These can be from 0-31. (I know that most of this is stuff you guys already know, but context...) How would I go about setting these bits to certain values? Normally, I'd use one of my favorite crates, bit_field, to do this, but what is the (non-dependency-required) way of doing this? I'm asking primarily because I'm obviously not going to manually write each function to decode/encode each instruction, and so I'm generating it (this post is related: that was needed so I could generate properly named Rust enumeration variants).
Would it be cleaner and easier to understand if I just used the bit_field crate and didn't have my generator generate a bunch of bit manipulation code? Or should I just have it generate the bit manipulation code and save on a dependency?

I feel you on the dependencies front, but bit_field looks like a single-file #[no_std] crate with zero transitive dependencies. I'd probably just use it if it does everything you need.


If you want to do it yourself anyway, you can see how they implemented BitField::set_bits. The more assumptions or values that are known, the more specific / less generic you could make it (e.g. you know your enum values are in range, pre-computed bitmasks and shift values, etc).

Not sure if this helps or is relevant, but I have 3 personal macros I use for bit manipulation:

// Bitfield  macros

/// The mask to extract $len bits at bit offset $off.
macro_rules! bitmask {
    ( $off: expr, $len: expr ) => {
        ((1 << $len) - 1) << $off
    };
}

/// Extract $len bits from $val at bit offset $off.
macro_rules! getbits {
    ( $val: expr, $off: expr, $len: expr ) => {
        ($val & bitmask!($off, $len)) >> $off
    };
}

/// Update $len bits in $var at bit offset $off to $val.
macro_rules! setbits {
    ( $var: expr, $off: expr, $len: expr, $val: expr ) => {
        $var = ($var & !bitmask!($off, $len)) | (($val << $off) & bitmask!($off, $len))
    };
}

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.