Skip to content
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

[Feature] Bitfield with inverse variable bit 'endianness' #2041

Open
1 task
Sewer56 opened this issue Dec 31, 2024 · 3 comments
Open
1 task

[Feature] Bitfield with inverse variable bit 'endianness' #2041

Sewer56 opened this issue Dec 31, 2024 · 3 comments

Comments

@Sewer56
Copy link

Sewer56 commented Dec 31, 2024

What feature would you like to see?

The ability to represent variables with inverse bit order, where the 'lowest' bit represents the 'highest' bit.
i.e. a bit sequence of 00001 (highest to lowest bit) should represent 32 (last bit is highest), and not 1 (last bit is lowest).

How will this feature be useful to you and others?

Some formats have bitfields whose fields are read in the following order:

  • Most to least significant bit (within a given byte)

    • ✅ This can be represented today by prepending be to a field declaration before a bitfield.
    • Mentioning this just so a reader doesn't get mixed up.
  • Treating the 'lowest' bit as the 'highest' (i.e. reversing bit order) at variable level.

    • ❌ I can't figure out if this is possible today; hence this issue.

In my case, I encountered a format with both.

The idea here being that the format is read as a bit 'stream' which is 'endian-free'. You read a bit (Most Significant Bit -> Least Significant Bit), shift an existing variable by 1, and OR the new value in. Therefore, the order of the bits within a field is reversed.

Request Type

  • I can provide a PoC for this feature or am willing to work on it myself and submit a PR

Additional context?

image

As an example, I've been trying to parse BC7 blocks docs 1 docs 2 in the DDS file format; after doing some things with BZip3 pattern; however, I'm unable to currently correctly represent the struct fields.

In this screenshot, the mode field should read 4 rather than 1; because it appears as the last bit [001]00000 in the byte; however it's interpreted as 1 instead. Same applies to other fields.

I have tried all permutations of [[bitfield_order]] attribute and be / le specifier; including also nesting structs with mixed endianness etc. Nothing appears to work.

In the case of the screenshot I used be on the field declaration with no attribute (it gets me the correct layout, just not ordering). I've also dug the wiki quite hard, but I cannot find the answer.

@Sewer56 Sewer56 changed the title [WIP: Still Editing Text] [Feature] Bitfield with inverse variable bit 'endianness' [Feature] Bitfield with inverse variable bit 'endianness' Dec 31, 2024
@paxcut
Copy link
Contributor

paxcut commented Dec 31, 2024

In terms of bitfield ordering the only feature implemented and described in the documentation is the ability to read the fields of a bitfield in either one of the two possible orders. There is no syntax provided that would allow reading the bits of a variable in the reverse order than the one expected. For variables the best you can do is choose endianness, but within each byte, bits are always read in the same order.
This doesn't mean you cant display the numbers that will correspond to the bit order reversal. You can use a format function to change the value to anything you want. Here is a simple bit reversal function for an 8 bit field. If you want to reverse 5 bits, pad it to 8 (that means just pretend it is 8) and shift the result to the right by 3 bits.
b5b4b3b2b1 pad =>000b5b4b3b2b1 reverse => b1b2b3b4b5000 shift => b1b2b3b4b5

fn reverse(auto b) {
   b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
   b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
   b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
   return b;
};

@Sewer56
Copy link
Author

Sewer56 commented Dec 31, 2024

Ah, that actually works thanks.

Given I'm still relatively very very new to ImHex, I didn't expect that you could apply a format function via attribute on the fields of a bitfield; some of the other modifiers I tried weren't available; so I didn't think you could apply regular attributes.

For anyone else reading, here's an example:

fn reverse3bits(u8 b) {
    b = (b & 0xF8) | ((b & 0x04) >> 2) | (b & 0x02) | ((b & 0x01) << 2);
    return b;
};

// Mode 2 structure (128 bits)
bitfield BC7BlockMode2 {
    unsigned mode      : 3 [[format("reverse3bits")]];    // Mode bits (001)
    unsigned partition : 6;    // Partition number
    // rest of bitfield.
}

That fixes the opening post's case.
In this case, you'd want a format function for every number of bits.

@paxcut
Copy link
Contributor

paxcut commented Dec 31, 2024

For reference and to give credit where's due hare's the place I got it from

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants