Search code examples
cbit-manipulationbitwise-operatorsbit-shiftbitwise-or

C - Bitwise concatenation causing missing information


I have five short type variables which I want to concatenate them into an 32 bits unsigned int type. I need to concatenate five short variables. The names of those variables are called opcode(5 bits), reg1(4 bits), reg2(4 bits), reg3(4 bits), extension(3 bits) and addr_constant(12 bits). Now my code does not work for one case which I do not know why. I listed my code below.

The purpose of this code is to translate certain values into a 32 bits machine instruction, which means even though I got the equivalent value, I still need to have a 32 bits instruction.

...
unsigned int *const word;
unsigned short opcode = 1;
unsigned short reg1 = 3; 
unsigned short reg2 = 4;
unsigned short reg3 = 5;
unsigned short extension = 0;
unsigned int addr_constant = 0;

unsigned int machine_word = 0;
machine_word = machine_word | (opcode << 27);
machine_word = machine_word | (reg1 << 23);
machine_word = machine_word | (reg2 << 19);
machine_word = machine_word | (reg3 << 15);

machine_word = machine_word | (extension << 12);
machine_word = machine_word | addr_constant;

*word = machine_word
return 0;
...

The output in binary form should be:

0000 1001 1010 0010 1000 0000 0000 0000.

But right now it is:

1001 1010 0010 1000 0000 0000 0000. 

As you can see, it misses the first 4 zeros.

In the following test "word" is: unsigned int *const word. And in the end of the code above, I wrote "*word = machine_word". In the test, it compares: "word == 0x09a28000" I failed the following test.

assert(word == 0x09a28000);

Solution

  • Maybe the issue is just the result interpretation. I've run the following code, which is based on the algorithm you provided with some modifications on the logical operations and the result printing. The core logic of the operation remains unvaried from what you posted, so maybe the result is misread.

    The code is the following:

    #include <stdio.h>
    
    int main() {
        int i, j, mask;
    
        unsigned short opcode = 1;
        unsigned short reg1 = 3; 
        unsigned short reg2 = 4;
        unsigned short reg3 = 5;
        unsigned short extension = 0;
        unsigned int addr_constant = 0;
    
        unsigned int machine_word = 0;
        machine_word |= opcode << 27;
        machine_word |= reg1 << 23;
        machine_word |= reg2 << 19;
        machine_word |= reg3 << 15;
    
        machine_word |= extension << 12;
        machine_word |= addr_constant;
    
        for (i = 7; i >= 0; i--) {
            for (j = 3; j >= 0; j--){
                printf("%d", (machine_word & 0x00000001 << (4 * i + j)) >> (4 * i + j));
            }
            printf(" ");
        }
        printf("\n");
        return 0;
    }
    

    The code gives the following output:

    0000 1001 1010 0010 1000 0000 0000 0000
    

    This should be the result your are searching for, it corresponds to the unsigned integer value of 161644544 (0x9A28000).