Search code examples
cbit-manipulationoperatorsbitwise-operatorsbit

Extract certain bits from A and replace only those extracted bits in B at a certain position


Extract and Modify bits
Pick n number of bits from a position in packed final_value and write into an arbitrary position without modifying original content of uint16_t test_bit = 0x3048. Expected output = 0x5048
For example: pick 010(3bits from position 17) from final_val and write into an arbitrary position(position 11)
0x3048 = 0111 0000 0100 1000;
0x5048 = 0101 0000 0100 1000

Few examples:
Example A:
Bold is the extracted. we extract bits 0 to 7 from Val_1, and replace only bits 0 to 7 in Val_2 leaving bits 8 to 15 as untouched.
Val_1 0x1b7 0000 0001 1011 0111
Val_2 0x27b7 0010 0111 1011 0111

Example B:
Extract 3 bits from Val1[from bits 8 to 10] and replace that in Val_2[from 11 to 13].
Val_1 0x129 0000 0001 0010 1001
Val_2 0x4C48 0100 1100 0100 1000
Tried so far:

#include <stdio.h>
#include <stdint.h>

void read_and_write(uint32_t* final_val, uint16_t* write_val, uint8_t start_pos, uint8_t end_pos)
{
    uint32_t temp = *final_val;
    *write_val = (uint16_t) ((temp >> start_pos) & ((1 << end_pos) - 1)); // store the desired number of bits in write_val
    *final_val = (temp >> end_pos); //shift final_val by end_pos since those bits are already written
    printf("\n temp %x, write_val %x, final_val %x ", temp, *write_val, *final_val);
    
}

void main() 
{
    uint32_t final_val = 0x0; //Stores 20 extracted bits from val1, val2 and val3 into final_val (LSB to MSB in order)
    uint16_t ext_val1 = 0x80;
    uint8_t ext_val2 = 0x0; 
    uint8_t ext_val3 = 0x2;
    final_val = (ext_val1 | (ext_val2 << 9) | (ext_val3 << 17));
    printf ("\n final_val %x", final_val);
    
    uint16_t data_1, data_2, data_3, write_val1, write_val2, write_val3;
    // Read first 9 bits of final_val and write only into [0:9] position of existing data_1
    uint8_t start_pos = 0;
    uint8_t end_pos = 9;
    data_1 = 0x80;
    read_and_write(&final_val, &write_val1, start_pos, end_pos);
    write_val1 = write_val1 | data_1;
    
    // Read next 8 bits of final_val and write only into [0:8] position of existing data_2
    start_pos = 0;
    end_pos = 8;
    data_2 = 0x27b7;
    read_and_write(&final_val, &write_val2, start_pos, end_pos);
    write_val2 = write_val2 | data_2;
    
    //Read next 3 bits of final_val and write only into[13:11] position of existing  data_3
    start_pos = 11;
    end_pos = 13;
    data_3 = 0x3048;
    read_and_write(&final_val, &write_val3, start_pos, end_pos);
    write_val3 = write_val3 | data_3;
    printf ("\n val1 0x%x val2 0x%x val3 0x%x final_val 0x%x", write_val1, write_val2, ext_val3, final_val);
}

Can someone please help with above? Ignore the stale code with the older approach.


Solution

  • Here is a simple implementation with helper functions and a test framework:

    • ((uint32_t)1 << n) - 1 computes the binary number 2n-1 that has the low n bits set.
    • uint32_t mask = (((uint32_t)1 << n) - 1) << pos2; computes mask with n bits set starting at position pos2.
    • (val2 & ~mask) clears the n bits at position pos2 of val2, leaving the other ones unchanged.
    • extract(val1, pos1, n) << pos2 moves the n bits extracted from val1 to position pos2, the other bits are 0.
    • or-ing these values computes the expected result, with the n bits from val1 copied starting at position pos2 in val2.

    Here is the code:

    #include <stdio.h>
    #include <stdint.h>
    
    uint32_t extract(uint32_t data, int pos, int n) {
        return (data >> pos) & (((uint32_t)1 << n) - 1);
    }
    
    uint32_t replace(uint32_t val1, uint32_t val2, int pos1, int n, int pos2) {
        uint32_t mask = (((uint32_t)1 << n) - 1) << pos2;
        return (val2 & ~mask) | (extract(val1, pos1, n) << pos2);
    }
    
    void test(uint32_t val1, uint32_t val2, int pos1, int n, int pos2) {
        uint32_t res = replace(val1, val2, pos1, n, pos2);
        printf("extracting bits [%d-%d] from 0x%04X to bits [%d-%d] in 0x%04X -> 0x%04X\n",
               pos1, pos1 + n - 1, val1, pos2, pos2 + n - 1, val2, res);
    }
    
    int main() {
        test(0x1234, 0x7048, 1, 3, 11);
        test(0x01b7, 0x2743, 0, 8, 0);
        test(0x0129, 0x7448, 8, 3, 11);
        return 0;
    }
    

    Output:

    extracting bits [1-3] from 0x1234 to bits [11-13] in 0x7048 -> 0x5048
    extracting bits [0-7] from 0x01B7 to bits [0-7] in 0x2743 -> 0x27B7
    extracting bits [8-10] from 0x0129 to bits [11-13] in 0x7448 -> 0x4C48