Bit manipulation, unnecessary mask? - c

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.

Related

Can anyone explain to me what this shifting means under this circumstance: uint16_t register0 = (instruction >> 9) & 0x7

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.

Most efficient way to check if flags are set in an integer

I have 11 flags defined as:
#define F1 1
#define F2 2
#define F3 3
#define F4 4
...
#define F11 11
In some function I then create an integer which can include either of those flags, for example:
int a = (1 << F1) | (1 << F5) | (1 << F11) | (1 << F8);
This then gets passed into a function which needs to decode which flags are set in order to set specific bits in specific registers. So my question is, what is the most efficient way to check which flags are set. Right now I have 11 if's like:
void foo(int a)
{
if ((a & (1 << F1)) >> F1) {
// Set bit 5 in register A.
}
if ((a & (1 << F2)) >> F2) {
// Set bit 3 in register V.
}
if ((a & (1 << F3)) >> F3) {
// Set bit 2 in register H.
}
if ((a & (1 << F4)) >> F4) {
// Set bit 1 in register V.
}
// And so on, for all 11 flags.
}
P.S.
This is for an 8-bit microcontroller.
Just use:
typedef enum{
FLAG1 = 1, // or 0x01
FLAG2 = 2,
FLAG3 = 4,
...
FLAG8 = 0x80
} flags;
Then in main just check
if(value & FLAGN)
In C there is no diffrence between 1 and any other number in if statement. It just check if is zero or non-zero number.
And setting is the same:
value = FLAG1 | FLAG2 | FLAG8;
You can also use defines ofc.
And for claryfication, max number of flags for N bit type is N. So you need to have larger type (if compiller supports bigger datatypes) like uint16_t.
C's if statement and logical operators do not make a difference between 1 and other non-zeros (although logical operators produce 1 for true). Therefore, there is no difference between (a & (1 << F3)) >> F3 and a & (1 << F3) in the context of a logical expression: if one evaluates to true, so does the other one, and vice versa. Hence, this should work:
if (a & (1 << F1)) {
// Set bit 5 in register A.
}
Note: I assume you didn't mean to write #define F11 1024, but rather #define F11 10, because you use your Fs as the second operand of <<.

How to read/write into specific bits of a unsigned char

I want to read and write from/to an unsigned char according to the table below:
for example I have following variables:
unsigned char hsi_div = 0x01; /* HSI/2 */
unsigned char cpu_div = 0x05; /* Fmaster/32 */
I want to write hsi_div to bits 4,3 and cpu_div to bits 2,1,0 (imagine the whole char is named CLK_DIVR):
CLK_DIVR |= hsi_div << 4; //not correct!
CLK_DIVR |= cpu_div << 2; //not correct!
And lets say I want to read the register back to make sure I did it correct:
if( ((CLK_DIVR << 4) - 1) & hsi_div) ) { /* SET OK */ }
if( ((CLK_DIVR << 2) - 1) & cpu_div) ) { /* SET OK */ }
Is there something wrong with my bitwise operations!? I do not get correct behaviour.
I assume CLK_DIVR is a hardware peripheral register which should be qualified volatile. Such registers should be set up with as few writes as possible. You change all write-able bits, so just
CLK_DIVR = (uint8_t)((hsi_div << 3) | (cpu_div << 0));
Note using fixed width type. That makes mentioniong it is an 8 bit register unnecessary. According to the excerpt, the upper bits are read-only, so they are not changed when writing. The cast keeps the compiler from issuing a truncation warning which is one of the recommended warnings to always enable (included in -Wconversion for gcc).
The shift count is actually the bit the field starts (the LSbit). A shift count of 0 means "no shifting", so the shift-operator is not required. I still use it to clarify I meant the field starts at bit 0. Just let the compiler optimize, concentrate on writing maintainable code.
Note: Your code bit-or's whatever already is in the register. Bit-or can only set bits, but not clear them. Addiionally the shift counts were wrong.
Not sure, but if the excerpt is for an ARM Cortex-M CPU (STM32Fxxxx?), reducing external bus-cycles becomes more relevant, as the ARM can take quite some cycles for an access.
For the HSIDIV bit fields you want:
hw_register = (hw_register & 0x18) | (hsi_value & 0x03) << 0x03;
This will mask the value to 2 bits wide then shift to bit position 3 and 4.
The CPUDIV fields are:
hw_register = (hw_register & 0x7) | (cpu_value & 7);
Reading the register:
hsi_value = (hw_register & 0x18) >> 3;
cpu_value = hw_register & 0x07;
Just
CLK_DIVR |= hsi_div << 3;
CLK_DIVR |= cpu_div << 0;
Since hsi_div is a 2-digit binary, you have to move it three positions to skip the CPUDIV field. And the cpu_div is already at the end of the field.

Switching bits in each nibble of an int

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;
}

How to break 32 bit value and assign it to three different data types.?

I have a
#define PROT_EN_DAT 0x140
//(320 in decimal)
Its loaded into 64 bit value register(ex setup_data[39:8]=PROT_EN_DATA)
Now i want to put this value(0x140)into
uint8_t bRequest
uint16_t wValue
uint16_t wIndex
How can load the value so that i don't have to manually do it for other values again.
I think we can do with shift operators but don know how.
EDIT:Ya its related to USB. bRequest(8:15),wValue(16:31),wIndex(32:47) but setup_data is 64 bit value.I want to know how can i load proper values into the these fields.
For example say next time i am using #define PROT_EN2_REG 0x1D8.
and say setup_data[39:8]=PROT_EN2_DATA
General read form:
aField = (aRegister >> kBitFieldLSBIndex) & ((1 << kBitFieldWidth) - 1)
General write form:
mask = ((1 << kBitFieldWidth) - 1) << kBitFieldLSBIndex;
aRegister = (aRegister & ~mask) | ((aField << kBitFieldLSBIndex) & mask);
where:
aRegister is the value you read from the bit-field-packed register,
kBitFieldLSBIndex is the index of the least significant bit of the bit field, and
kBitFieldWidth is the width of the bit field, and
aField is the value of the bit field
These are generalized, and some operations (such as bit-masking) may be unnecessary in your case. Replace the 1 with 1L if the register is larger than 32 bits.
EDIT: In your example case (setup_data[39:8]=PROT_EN_DATA):
Read:
aField = (setup_data >> 8) & ((1L << 32) - 1L)
Write:
#define PROT_EN_MASK = (((1L << 32) - 1L) << 8) // 0x0000000FFFFFFFF0
setup_data = (setup_data & ~PROT_EN_MASK) | ((PROT_EN_DATA << 8) & PROT_EN_MASK);

Resources