So I have a pointer to a uint8_t array in the form of:
uint8_t* array; // 64-bit array
I need to modify this array by shifting bits to the right and inserting a bit of 0 or 1 at indexes with a power of 2. Thereby generating a 72-bit array.
uint8_t newArr[9];
What is the best way to modify an array so I can add the bits at the specific places I computed. I thought of converting the array to a a char array and then adding the bits one by one. However, is there a faster and more easier method than this.
So if I have a pointer to a bit array in the form of uint8_t like:
000100001 11001111 01101101 11000001 11100000 00101111 11111001 10010010
I would need to modify it into a uint8_t[9] array so that I insert bits I have specified at 0, 1, 2, 4, 8, 16, 32, 64 of the new array to look like: (answer is wrong)
00000000 11001111 11001111 11001111 11001111 01101101 01101101 10010010 00100001
But I don't know how to shift a particular bit to the right without shifting all the bits. For example if I shift all bits starting at index 2 1 to the right and then all bits starting from index 4 to the right by one.
Say you start with the following:
src[0] src[1] src[2] src[3] src[4] src[5] src[6] src[7]
-------- -------- -------- -------- -------- -------- -------- --------
7 6 5 4 3 2 1
76543210 76543210 76543210 76543210 76543210 76543210 76543210 76543210
aaaaaaaa bbbbbbbb cccccccc dddddddd eeeeeeee ffffffff gggggggg hhhhhhhh
You want to insert at the following positions (octal):
0, 1, 2, 4, 10, 20, 40, 100
That means you want the following:
dst[0] dst[1] dst[2] dst[3] dst[4] dst[5] dst[6] dst[7] dst[8]
-------- -------- -------- -------- -------- -------- -------- -------- --------
1
0 7 6 5 4 3 2 1
76543210 76543210 76543210 76543210 76543210 76543210 76543210 76543210 76543210
aaaaaaa0 abbbbbbb bccccccc cddddddd deeeeee0 eeffffff ffggggg0 ggghhhh0 hhh0h000
So,
dst[0] = src[0] & 0xFE;
dst[1] = ((src[0] ) << 7) | ((src[1] ) >> 1);
dst[2] = ((src[1] ) << 7) | ((src[2] ) >> 1);
dst[3] = ((src[2] ) << 7) | ((src[3] ) >> 1);
dst[4] = ((src[3] ) << 7) | ((src[4] & 0xFC) >> 1);
dst[5] = ((src[4] ) << 6) | ((src[5] ) >> 2);
dst[6] = ((src[5] ) << 6) | ((src[6] & 0xFC) >> 2);
dst[7] = ((src[6] ) << 5) | ((src[7] & 0xFC) >> 3);
dst[8] = ((src[7] & 0x0E) << 5) | ((src[7] & 0x01) << 3);
(Useless masks omitted.)
You can treat the input array as a 64-bit int to make it faster. Suppose the input and output values are like this
array = aaaaaaaa bbbbbbbb cccccccc dddddddd eeeeeeee ffffffff gggggggg hhhhhhhh
newArr = aaaaaaa0 abbbbbbb bccccccc cddddddd deeeeee0 eeffffff ffggggg0 ggghhhh0 hhh0h000
Then you can get the desired result using this way
uin64_t src = htobe64(*(uint64_t*)array); // operate on big endian
uint64_t* dst = (uint64_t*)newArr;
*dst = (src & 0xFE00'0000'0000'0000) >> 0; // aaaaaaa
*dst |= (src & 0x01FF'FFFF'FC00'0000) >> 1; // abbbbbbbbccccccccddddddddeeeeee
*dst |= (src & 0x0000'0000'03FF'F800) >> 2; // eeffffffffggggg
*dst |= (src & 0x0000'0000'0000'07F0) >> 3; // ggghhhh
*dst = be64toh(*dst); // convert back to the native endian
newArr[8] = ((array[7] & 0x0E) << 4) | ((array[7] & 0x01) << 3); // hhh0h000
To avoid strict aliasing you can change to memcpy to copy from array to src and from dst to newArr
Of course you may need to align the input and output arrays for better performance. On many modern architectures it's also a must
#ifdef _MSC_VER
__declspec(align(8)) uint8_t array[8]; // 64-bit array
__declspec(align(8)) uint8_t newArr[9];
#else
uint8_t array[8] __attribute__((aligned(8))); // 64-bit array
uint8_t newArr[9] __attribute__((aligned(8)));
#endif
On modern x86 with BMI2 you can use the new bit deposit instruction to get the first 8 bytes directly
uint64_t src;
memcpy(&src, &array, sizeof src); // avoid strict aliasing
uin64_t src = htobe64(src);
uint64_t dst = _pdep_u64(src >> 4,
// aaaaaaa0 abbbbbbb bccccccc cddddddd deeeeee0 eeffffff ffggggg0 ggghhhh0
0b11111110'11111111'11111111'11111111'11111110'11111111'11111110'11111110);
// hhh0h000
newArr[8] = _pdep_u32(src, 0b11101000);
*dst = be64toh(*dst); // convert back to the native endian
memcpy(&newArr, &dst, sizeof dst); // avoid strict aliasing
Related
I'm trying to write a VM (LC-3), and on this ADD instruction I encountered this statement. Basically the "register0" is the DR register, but I don't really understand what is actually shifting and why 9. Also the AND operator with the 0x7 value.
|15|14|13|12|11|10|9|8|7|6|5|4|3|2|1|0|
| 0001 | DR | SR1 |0| 00| SR2 |
Could anyone please explain it to me in detail?
ADD {
/* destination register (DR) */
uint16_t r0 = (instr >> 9) & 0x7;
/* first operand (SR1) */
uint16_t r1 = (instr >> 6) & 0x7;
/* whether we are in immediate mode */
uint16_t imm_flag = (instr >> 5) & 0x1;
if (imm_flag) {
uint16_t imm5 = sign_extend(instr & 0x1F, 5);
reg[r0] = reg[r1] + imm5;
} else {
uint16_t r2 = instr & 0x7;
reg[r0] = reg[r1] + reg[r2];
}
update_flags(r0);
}
What it's doing is isolating the 3 bits that represent the DR register so they become a standalone number.
Let's say the entire sequence looks like this:
1110101101101011
^^^
DR
Shifting 9 bits right gives this:
1110101
and & 0x7 (bitwise AND) isolates the 3 lowest bits:
101
Similar operations are performed to isolate the values of SR1 and the immediate mode flag. Depending on that flag, SR2 may also be required, but as it's already in the lowest 3 bits, no shifting is needed.
I'm trying to read the pressure value from MPL3115.
At chapter 14.3 the ds says:
The pressure data is stored as a 20-bit unsigned integer with a fractional part. The
OUT_P_MSB (01h), OUT_P_CSB (02h) and bits 7 to 6 of the OUT_P_LSB (03h)
registers contain the integer part in Pascals. Bits 5 to 4 of OUT_P_LSB contain the
fractional component. This value is representative as a Q18.2 fixed point format where
there are 18 integer bits and two fractional bits.
Here my (testing) code for Microchip XMEGA (GCC):
#define MPL3115_ADDRESS 0x60
#define MPL3115_REG_PRESSURE_DATA 0x01
bool _ReadRegister(uint8_t address, uint8_t *readBuf, uint8_t readCount)
{
TWI_MasterWriteRead(&twiMaster, MPL3115_ADDRESS, &address, 1, readCount);
while (twiMaster.status != TWIM_STATUS_READY);
memcpy(readBuf, (void *) twiMaster.readData, readCount);
return true;
}
bool MPL3115_ReadPressure(float *value) {
uint8_t raw[3];
_ReadRegister(MPL3115_REG_PRESSURE_DATA, raw, 3);
uint32_t data = (((uint32_t) raw[0]) << 16) | (((uint32_t) raw[1]) << 8) | raw[2];
uint32_t q18n2 = data >> 4;
*value = (double) q18n2 / 4;
return true;
}
I'm pretty sure the i2c line is working because I can successfully read the temperature from the same chip.
I configured it in barometer mode and 128 oversampling (CTRL_REG1 = 0x38).
In debug mode I read the following values:
raw0 = 0x18
raw1 = 0x25
raw2 = 0x70
data = 1582448
to obtain the pressure in Pascal I have to right shift data of 4 bits:
q18n2 = 98908
now to convert the Q18.2 to float I should multiply for 2^-n or divide for 4:
value = 24727 Pa
This should be in Pascal, so divide for 100 and get mBar = 247.27 mBar... it's unlikely I have such a pressure here! By the way now should be around 1008 mBar.
Are there any mistakes in my thoughts?
you must to right shift data of 6 bits and then add fractional part (2 bits * 0.25).
*value = (raw0 << 10) | (raw1 << 2) | (raw2 >> 6);
*value += 0.25 * ((raw2 >> 4) & 0x03);
I'm trying to get a hold of bit manipulation in embedded c programming.
I have the following code
#define X_POS (8UL)
#define X_MASK (0x1FUL<<X_POS)
#define Y_POS (16UL)
#define Y_MASK (0x3UL<<Y_POS)
typedef struct {
uint32_t res[6];
uint32_t config[10];
} myStruct_type;
myStruct_type myStruct;
void configure (uint32_t n, uint32_t x, uint32_t y)
{
myStruct.config[n] &= ~(X_MASK | Y_MASK); // A
myStruct.config[n] |= ((x<<X_POS) & X_MASK) | ((y<<Y_POS) & Y_MASK); // B
}
int main (void)
{
configure(3, 18, 2);
while (1) { }
}
I understand that the line marked with the comment A is used for setting the bits of interest to 0, i.e. clearing the bits.
Also I understand that on the line marked with B the bits of interest are set to wanted values.
But what is the purpose of the X_MASK and Y_MASK on line B??? Aren't the values set by
(x<<X_POS) | (y<<Y_POS)
The purpose of the masking on line B is to ensure that only the bits you want set will be set. e.g. if x is 0xFFFFFFFF, the & with X_MASK will stop the bits above what you are interested in from being set.
So assuming config[0] starts out at 0, x is 0xFFFFFFFF and y is 0, without the maskingin line B, you would have
myStruct.config[0] &= ~(X_MASK | Y_MASK); // config[0] is still 0
myStruct.config[0] |= (0xFFFFFFFF << 8) | (0<< 16);
// config[0] is now 0xFFFFFF00
with the masks, the second line is
myStruct.config[0] |= ((0xFFFFFFFF<< 8) & 0x1F00) | (( 0 << 16) & 3 << 16); // B
which is
myStruct.config[0] |= 0x1F00 | 0);
If you only use (x<<X_POS) | (y<<Y_POS) you simply assign the values x and y shifted to the left.
The mask eliminates the unwanted bits. For example:
X_MASK = 0x1FUL << 8UL = 0x1F00000000 = 0b111110000...
With the logical & (AND) you set all bits to zero that are zero on your mask:
X_MASK 0b00000001111100000000.....
x<<X_POS 0b01010101010100000000.....
& ________________________
result 0b00000001010100000000.....
On a higher level you can say, that the X_MASK sets all bits of x to zero except the lowest 5 and the Y_MASK sets all bits of y to zero, except the lowest 2. Afterwards your result gets bit shifted to the left. So the mask will clear the higher bits.
How can I switch the 0th and 3rd bits of each nibble in an integer using only bit operations (no control structures)? What kind of masks do I need to create in order to solve this problem? Any help would be appreciated. For example, 8(1000) become 1(0001).
/*
* SwitchBits(0) = 0
* SwitchBits(8) = 1
* SwitchBits(0x812) = 0x182
* SwitchBits(0x12345678) = 0x82a4c6e1
* Legal Operations: ! ~ & ^ | + << >>
*/
int SwitchBits(int n) {
}
Code:
#include <stdio.h>
#include <inttypes.h>
static uint32_t SwitchBits(uint32_t n)
{
uint32_t bit0_mask = 0x11111111;
uint32_t bit3_mask = 0x88888888;
uint32_t v_bit0 = n & bit0_mask;
uint32_t v_bit3 = n & bit3_mask;
n &= ~(bit0_mask | bit3_mask);
n |= (v_bit0 << 3) | (v_bit3 >> 3);
return n;
}
int main(void)
{
uint32_t i_values[] = { 0, 8, 0x812, 0x12345678, 0x9ABCDEF0 };
uint32_t o_values[] = { 0, 1, 0x182, 0x82A4C6E1, 0x93B5D7F0 };
enum { N_VALUES = sizeof(o_values) / sizeof(o_values[0]) };
for (int i = 0; i < N_VALUES; i++)
{
printf("0x%.8" PRIX32 " => 0x%.8" PRIX32 " (vs 0x%.8" PRIX32 ")\n",
i_values[i], SwitchBits(i_values[i]), o_values[i]);
}
return 0;
}
Output:
0x00000000 => 0x00000000 (vs 0x00000000)
0x00000008 => 0x00000001 (vs 0x00000001)
0x00000812 => 0x00000182 (vs 0x00000182)
0x12345678 => 0x82A4C6E1 (vs 0x82A4C6E1)
0x9ABCDEF0 => 0x93B5D7F0 (vs 0x93B5D7F0)
Note the use of uint32_t to avoid undefined behaviour with sign bits in signed integers.
To obtain a bit, you can mask it out using AND. To get the lowest bit, for example:
x & 0x01
Think about how AND works: both bits must be set. Since we're ANDing with 1, all bits except the first must be 0, because they're 0 in 0x01. The lowest bit will be either 0 or 1, depending on what's in x; said differently, the lowest bit will be the lowest bit in x, which is what we want. Visually:
x = abcd
AND 1 = 0001
--------
000d
(where abcd represent the bits in those slots; we don't know what they are)
To move it to bit 3's position, just shift it:
(x & 0x01) << 3
Visually, again:
x & 0x01 = 000d
<< 3
-----------
d000
To add it in, first, we need to clear out that spot in x for our bit. We use AND again:
x & ~0x08
Here, we invert 0x08 (which is 1000 in binary): this means all bits except bit 3 are set, and when we AND that with x, we get x except for that bit.
Visually,
0x08 = 1000
(invert)
-----------
0111
AND x = abcd
------------
0bcd
Combine with OR:
(x & ~0x08) | ((x & 0x01) << 3)
Visually,
x & ~0x08 = 0bcd
| ((x & 0x01) << 3) = d000
--------------------------
dbcd
Now, this only moves bit 0 to bit 3, and just overwrites bit 3. We still need to do bit 3 → 0. That's simply another:
x & 0x08 >> 3
And we need to clear out its spot:
x & ~0x01
We can combine the two clearing pieces:
x & ~0x09
And then:
(x & ~0x09) | ((x & 0x01) << 3) | ((x & 0x08) >> 3)
That of course handles only the lowest nibble. I'll leave the others as an exercise.
Try below code . Here you should know bitwise operator to implement and correct position to place.Also needs to aware of maintenance ,shifting and toggling basic properties.
#include<stdio.h>
#define BITS_SWAP(x) x=(((x & 0x88888888)>>3) | ((x & 0x11111111)<<3)) | ((x & ~ (0x88888888 | 0x11111111)))
int main()
{
int data=0;
printf("enter the data in hex=0x");
scanf("%x",&data);
printf("bits=%x",BITS_SWAP(data));
return 0;
}
OP
vinay#vinay-VirtualBox:~/c_skill$ ./a.out
enter the data in hex=0x1
bits=8
vinay#vinay-VirtualBox:~/c_skill$ ./a.out
enter the data in hex=0x812
bits=182
vinay#vinay-VirtualBox:~/c_skill$ ./a.out
enter the data in hex=0x12345678
bits=82a4c6e1
vinay#vinay-VirtualBox:~/c_skill$
Try this variant of the xor swap:
uint32_t switch_bits(uint32_t a){
static const mask = 0x11111111;
a ^= (a & mask) << 3;
a ^= (a >> 3) & mask;
a ^= (a & mask) << 3;
return a;
}
Move the low bits to the high bits and mask out the resulting bits.
Move the high bits to the low bits and mask out the resulting bits.
Mask out all bits that have not been moved.
Combine the results with ORs.
Code:
unsigned SwitchBits(unsigned n) {
return ((n << 3) & 0x88888888) | ((n >> 3) & 0x11111111) | (n & 0x66666666);
}
Alternativly, if you would like to be very clever. It can be done with two fewer operations, though this may not actually be faster due to some of the dependicies between instrutions.
Move the high bits to align with the low bits
XOR recording a 0 in the low bit if high an low bits are the same, and a 1 if they are different.
From this, mask out only the low bit of each nibble.
From this, multiply by 9, this will keep the low bit as is, and also copy it to the high bit.
From this, XOR with the original value. in the case that the high and low bit are the same, no change will correctly occure. In the case they are different, they will be effectivly exchanged.
Code:
unsigned SwitchBits(unsigned n) {
return ((((n >> 3) ^ n) & 0x11111111) * 0x9) ^ n;
}
I have a unsigned char array[248]; filled with bytes. Like 2F AF FF 00 EB AB CD EF .....
This Array is my Byte Stream which I store my Data from the UART (RS232) as a Buffer.
Now I want to convert the bytes back to my uint16's and int32's.
In C# I used the BitConverter Class to do this. e.g:
byte[] Array = { 0A, AB, CD, 25 };
int myint1 = BitConverter.ToInt32(bytes, 0);
int myint2 = BitConverter.ToInt32(bytes, 4);
int myint3 = BitConverter.ToInt32(bytes, 8);
int myint4 = BitConverter.ToInt32(bytes, 12);
//...
enter code here
Console.WriteLine("int: {0}", myint1); //output Data...
Is there a similiar Function in C ? (no .net , I use the KEIL compiler because code is running on a microcontroller)
With Regards
Sam
There's no standard function to do it for you in C. You'll have to assemble the bytes back into your 16- and 32-bit integers yourself. Be careful about endianness!
Here's a simple little-endian example:
extern uint8_t *bytes;
uint32_t myInt1 = bytes[0] + (bytes[1] << 8) + (bytes[2] << 16) + (bytes[3] << 24);
For a big-endian system, it's just the opposite order:
uint32_t myInt1 = (bytes[0] << 24) + (bytes[1] << 16) + (bytes[2] << 8) + bytes[3];
You might be able to get away with:
uint32_t myInt1 = *(uint32_t *)bytes;
If you're careful about alignment issues.
Yes there is. Assume your bytes are in:
uint8_t bytes[N] = { /* whatever */ };
We know that, a 16 bit integer is just two 8 bit integers concatenated, i.e. one has a multiple of 256 or alternatively is shifted by 8:
uint16_t sixteen[N/2];
for (i = 0; i < N; i += 2)
sixteen[i/2] = bytes[i] | (uint16_t)bytes[i+1] << 8;
// assuming you have read your bytes little-endian
Similarly for 32 bits:
uint32_t thirty_two[N/4];
for (i = 0; i < N; i += 4)
thirty_two[i/4] = bytes[i] | (uint32_t)bytes[i+1] << 8
| (uint32_t)bytes[i+2] << 16 | (uint32_t)bytes[i+3] << 24;
// same assumption
If the bytes are read big-endian, of course you reverse the order:
bytes[i+1] | (uint16_t)bytes[i] << 8
and
bytes[i+3] | (uint32_t)bytes[i+2] << 8
| (uint32_t)bytes[i+1] << 16 | (uint32_t)bytes[i] << 24
Note that there's a difference between the endian-ness in the stored integer and the endian-ness of the running architecture. The endian-ness referred to in this answer is of the stored integer, i.e., the contents of bytes. The solutions are independent of the endian-ness of the running architecture since endian-ness is taken care of when shifting.
In case of little-endian, can't you just use memcpy?
memcpy((char*)&myint1, aesData.inputData[startindex], length);
char letter = 'A';
size_t filter = letter;
filter = (filter << 8 | filter);
filter = (filter << 16 | filter);
filter = (filter << 32 | filter);
printf("filter: %#I64x \n", filter);
result: "filter: 0x4141414141414141"