Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overlapped bit-field in C

I'm a computer science student.

Now, I'm working on a computer architecture project in C, which simulates a processor.

There are many types of instructions such as

 31     27 26     22 21     17 16                              0
 ---------------------------------------------------------------
|    op   |    ra   |    rb   |             imm17               |
 ---------------------------------------------------------------

 31     27 26     22 21     17 16                7 6 5 4       0
 ---------------------------------------------------------------
|    op   |    ra   |    rb   |       imm10       | m |  shamt  |
 ---------------------------------------------------------------

 31     27 26     22 21                                        0
 ---------------------------------------------------------------
|    op   |    ra   |                  imm22                    |
 ---------------------------------------------------------------

So, I wanted to make a C structure which contains bit-fields corresponding to each elements such as op, ra and so on.

At first, I thought that I could use unions and nested structs.

For example, I wrote code like:

struct instr_t {
    union {
        uint32_t imm22 : 22;

        struct {
            union {
                uint32_t imm17: 17;
                struct {
                    uint8_t shamt: 5;
                    uint8_t mode : 2;
                    uint16_t imm10 : 10;
                };
            };
            uint8_t rb : 5;
        };
    };

    uint8_t ra : 5;
    uint8_t op : 5;
}

I expected that the result of sizeof(struct instr_t) would be 4 but the reality was 12.

Maybe the nested structs got some paddings.

So, here is my qeustion:

How can one achieve overlapped C bit-fields?

or

Does anybody can recommend a better way to implement multiple types of instruction in C?

Thank you!

like image 775
lbyeoksan Avatar asked Feb 11 '23 18:02

lbyeoksan


1 Answers

The bit-fields members must be stored in the same storage unit to be layed out contiguously:

struct instr_1_t {
    uint32_t imm22 : 17;
    uint32_t rb : 5;
    uint32_t ra : 5;
    uint32_t op : 5;
};

struct instr_2_t {
    uint32_t shamt: 5;
    uint32_t m: 2;
    uint32_t imm10 : 10;
    uint32_t rb : 5;
    uint32_t ra : 5;
    uint32_t op : 5;
};

struct instr_3_t {
    uint32_t imm22 : 22;
    uint32_t ra : 5;
    uint32_t op : 5;
};

union instr_t {
    struct {
        uint32_t pad : 22;
        uint32_t op : 5;
    };
    instr_1_t instr_1;
    instr_2_t instr_2;
    instr_3_t instr_3;
};

static_assert(sizeof(instr_t) == sizeof(uint32_t), "sizeof(instr_t) != sizeof(uint32_t)");

void handle_instr(instr_t i) {
    switch(i.op) {
        //
    }
}
like image 103
Maxim Egorushkin Avatar answered Feb 16 '23 02:02

Maxim Egorushkin