How to change a 32bit registers specific bits without changing other bits? - c

I want to manipulate some bits of a register directly using its physical address. However I couldn't find a way to make this. I saw some posts about setting bit masks but I find them too confusing.
My registers physical address is: 0x4A10005C
I want to manipulate its bit which was between 18-16 bits. I want to set 0x3 inside those bits.
I will be really glad if you guys can provide an answer or a way to do it. Thanks.

You can just define a pointer to the register and then use normal C bitwise operations to manipulate the individual bits:
volatile uint32_t * const my_register = (uint32_t *) 0x4A10005C;
// set up a pointer to the register
uint32_t val = *my_register; // read register
val &= ~(0x7 << 16); // clear bits 16..18
val |= (0x3 << 16); // set bits 16..18 to 0x03 (i.e. set bits 16 and 17)
*my_register = val; // write register
(The above assumes that you are talking about three bits within the register, bits 16, 17 and 18, and that you want to set bit 18 to zero and bits 16 and 17 to 1.)

bit masks are pretty easy to understand so let’s run through that first:
Let say your 32bit register contains some value right now I'll arbitrarily pick 0xF48C621916
I assume you know how to convert hex to binary, if not... let's just say use a calculator or google (rather than go into the nitty gritty of that too). So our hex value can be represented in binary as:
+-- bit 31 +-- bit 0
| |
v v
1111 0100 1000 1100 0110 0010 0001 1001
^ ^
| |
+-+-- bits you want to set, 16-18
Boolean logic tells us that:
1) anything OR'd (|) with 1 gives you a value of 1. Or "sets" the bit.
2) anything AND'd (&) with 0 gives you a value of 0. Or "clears" the bit.
So if we wanted to clear bits 16-18 you can AND it with a mask like:
base number: 1111 0100 1000 1100 0110 0010 0001 10012 == 0xF48C621916
mask number: 1111 1111 1111 1000 1111 1111 1111 11112 == 0xFFF8FFF16
1111 0100 1000 1100 0110 0010 0001 1001
& 1111 1111 1111 1000 1111 1111 1111 1111
------------------------------------------
1111 0100 1000 1000 0110 0010 0001 1001
Now you can OR it with whatever you want to set there:
new mask number: 0000 0000 0000 0011 0000 0000 0000 00002 == 0x0003000016
1111 0100 1000 1000 0110 0010 0001 1001
| 0000 0000 0000 0011 0000 0000 0000 0000
-----------------------------------------
1111 0100 1000 1011 0110 0010 0001 1001
So in the code:
#define CLEAR_MASK 0x70000 //70000 is shorter to write, so just do this and flip it
#define SET_3_MASK 0x30000
volatile uint32_t * const reg = (uint32_t *) 0x4A10005C;//set a pointer to the register
*reg &= ~CLEAR_MASK; //~ filps the bits
*reg |= SET_3_MASK;
You can do tricks with shifting bits and so forth, but this is the basics of bit masks and how they work. Hope it helps.

structure r32 {
unsigned int bit0 :1;
unsigned int bit1 :1;
unsigned int bit2 :1;
unsigned int bit3 :1;
unsigned int bit4 :1;
unsigned int bit5 :1;
.
.
.
unsigned int bit31 :1;
}
in your main
structure r32 *p;
volatile uint32_t * const my_register = (uint32_t *) 0x4A10005C;
p = (structure r32 *) my_register;
and then to access to bit 5 for example
p->bit4 = 0;

Related

How can I clear half a byte from a number

I know I can clear a single bit by using the bitwise operator &
number &= ~(1 << x);
But how would I be able to clear either the upper or lower half of a byte?
For example, number = 99
99 = 0110 0011 and clearing the upper half we get 0000 0011
Just AND the byte with the mask you need: to clear the upper four bits, use n & 0x0F, to clear the lower four bits, use n & 0xF0.
You could say number &= 15;. 15 is represented as 0000 1111 in binary which means the leading/upper 4 bits would be cleared away.
Likewise, to clear the trailing/lower 4 bits, you could then say number &= 240 because 240 is represented as 1111 0000 in binary.
For example, let's say number = 170 and we want to clear away the leading/upper four bits. 170 is represented as 1010 1010 in binary. So, if we do number &= 15, we get:
1010 1010
& 0000 1111
-------------
0000 1010
(0000 1010 is 10 in binary)
Supposing, again, number = 170 and we want to clear the trailing/lower four bits, we can say: number &= 240. When we do this, we get:
1010 1010
& 1111 0000
-------------
1010 0000
(1010 0000 is 160 in binary)
You want to do an and with the bit-pattern showing what you want to keep.
So for your case:
number &= 0xf;
As 0xf is 0000 1111.
This is sometimes referred to as a "mask".
Clear lower half:
number &= ~0xF;
Higher half:
number &= ~0xF0;
The above works work int types. For larger types, you need to extend mask accordingly, for example:
number &= ~UINT64_C(0xF0);

bitwise operations in c explanation

I have the following code in c:
unsigned int a = 60; /* 60 = 0011 1100 */
int c = 0;
c = ~a; /*-61 = 1100 0011 */
printf("c = ~a = %d\n", c );
c = a << 2; /* 240 = 1111 0000 */
printf("c = a << 2 = %d\n", c );
The first output is -61 while the second one is 240. Why the first printf computes the two's complement of 1100 0011 while the second one just converts 1111 0000 to its decimal equivalent?
You have assumed that an int is only 8 bits wide. This is probably not the case on your system, which is likely to use 16 or 32 bits for int.
In the first example, all the bits are inverted. This is actually a straight inversion, not two's complement:
1111 1111 1111 1111 1111 1111 1100 0011 (32-bit)
1111 1111 1100 0011 (16-bit)
In the second example, when you shift it left by 2, the highest-order bit is still zero. You have misled yourself by depicting the numbers as 8 bits in your comments.
0000 0000 0000 0000 0000 0000 1111 0000 (32-bit)
0000 0000 1111 0000 (16-bit)
Try to avoid doing bitwise operations with signed integers -- often it'll lead you into undefined behavior.
The situation here is that you're taking unsigned values and assigning them to a signed variable. For ~60 this is undefined behavior. You see it as -61 because the bit pattern ~60 is also the two's-complement representation of -61. On the other hand 60 << 2 comes out correct because 240 has the same representation both as a signed and unsigned integer.

Logic of a bit masking XOR code

I have a code that changes two sets of hex numbers and then stores them into a new unsigned char. The code looks like the following:
unsigned char OldSw = 0x1D;
unsigned char NewSw = 0xF0;
unsgined char ChangedSw;
ChangedSw = (OldSw ^ ~NewSw) & ~OldSw;
So what I know is:
0x1D = 0001 1101
0xF0 = 1111 0000
Im confused on what the changedSw line is doing. I know it will give the output 0x02 but I can not figure out how its doing it.
ChangedSw = (OldSw ^ ~NewSw) & ~OldSw;
It means "zero one part of OldSw and inverse other part". NewSw indicates what bits of OldSw to zero and what bits to inverse. Namely, 1's in NewSw indicate bits to be zeroed, 0's indicate bits to be inverted.
This operation implemented in two steps.
Step 1. Invert bits.
(OldSw ^ ~NewSw):
0001 1101
^ 0000 1111
---------
0001 0010
See, we inverted bits which were 0's in original NewSw.
Step 2. Zero bits which were not inverted in previous step.
& ~OldSw:
0001 0010
& 1110 0010
---------
0000 0010
See, it doesn't change inverted bits, but zero all the rest.
the first part would be 1F ie. 0001 1111.So when ended with ~oldsw(1110 0010)
the operation will be something like this:
0001 1111
1110 0010
----------
0000 0010
So the output will be 2. The tilde operator is 1's complement.

Sign-extend a number in C

I am having trouble trying to sign-extend a number by extracting part of a bit-string. This has trouble when it is a negative number, it wraps the number around to the positive side.
Here is my code:
// printf("add1 \n");
unsigned short r1 = (instruction>>6)&7;
signed short amount = (instruction& 31); //right here! i am trying to get the last 5 bits and store it in a register but i can't figure out how to make it negative if it is negative
// printf("\namount is %d \n", amount);
unsigned short dest = (instruction>>9)&7;
state->regs[dest] = state->regs[r1]+amount;
setCC(state,state->regs[r1]+amount);
For bit patterns, it's often easier to use hex constants instead of decimal.
signed short amount = (instruction & 0x1F);
Then to sign-extend the number, check the sign-bit (assuming the sign-bit here is the left-most of the 5 extracted bits). If it's set, do a binary inversion and add 1. Take the 2's-complement of the 5-bit value (invert and add one), then take the 2's-complement of the full-width result (invert and add 1).
if (amount & 0x10)
amount = ~(amount^0x1F + 1) + 1;
Eg.
5-bit "bitfield"
X XXXX
0000 0000 0001 1111
0000 0000 0000 0000 invert x ^ 0x1F (= 1 1111)
0000 0000 0000 0001 add 1
1111 1111 1111 1110 invert ~
1111 1111 1111 1111 add 1
0000 0000 0001 0000
0000 0000 0000 1111 invert x ^ 0x1F (= 1 1111)
0000 0000 0001 0000 add 1
1111 1111 1110 1111 invert ~
1111 1111 1111 0000 add 1
Ooops. Even simpler:
-(x^0x1F + 1) Assuming the machine operates with 2's-complement
0000 0000 0001 0110
0000 0000 0000 1001 invert
0000 0000 0000 1010 add 1 (yielding the full-width absolute value)
1111 1111 1111 0110 negate
use bitfields:
union {
int a;
struct {
int a:5;
int b:3;
unsigned int c:20;
} b;
} u = 0xdeadbeef;
int b = u.b.b; // should sign extend the 3-bit bitfield starting from bit 5
Here is how you can sign extend a 5-bit two's complement value portably without tests:
int amount = (instruction & 31) - ((instruction & 16) << 1);
More generally, it the field width is n, non zero and less than the number of bits in an int, you can write:
int amount = (instruction & ~(~1U << (n - 1) << 1)) -
((instruction & (1U << (n - 1)) << 1);
From Hacker's Delight 2-6. Assuming 5 bits of data that must be sign extended (sign bit has value 16).
Best case: If the upper bits are all zeros:
(i ^ 16) - 16
Next best case (as with OP's instruction): If the upper bits contain data that must be discarded:
(i & 15) - (i & 16)
You can check the sign-bit and fix-up the result accordingly:
int width_of_field = 5;
signed short amount = (instruction& 31);
if (amount & (1 << width_of_field >> 1)) // look at the sign bit
{
amount -= 1 << width_of_field; // fix the result
}
Alternatively, use a left-shift followed by a right shift:
width_of_field = 5;
signed short amount = (instruction& 31);
// It is possible to omit the "& 31", because of the left shift below
amount <<= 16 - width_of_field;
amount >>= 16 - width_of_field;
Note: must use two statements to avoid effects of promotion to int (which presumably has 32 bits).

set the m-bit to n-bit [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
I have a 32-bit number and without using for loop, I want to set m bit to n bits.
For example:
m bit may be 2nd or 5th or 9th or 10th.
n bit may be 22nd or 27 or 11th bit.
I assume (m < n).
Please help me.Thanks
Suppose Bits are numbered from LSB to MSB:
BIT NUMBER 31 0
▼ ▼
number bits 0000 0000 0000 0000 0000 0000 0001 0101
▲ ^ ^ ▲
MSB | | LSB
| |
n=27 m=17
LSB - Least Significant Bit (numbered 0)
MSB - Most Significant Bit (numbered 31)
In the figure above, I have shown how bits are numbered from LSB to MSB.
Notice the relative positions of n and m where n > m.
To set (all one) bits from n to m
To set-1 all bits from position m to n (where n > m) in a 32-bit number.
You need a 32-bit mask in which all bits are 1 from n to m and remaining bits are 0.
For example, to set all bits from m=17 to n=27 we need mask like:
BIT NUMBER 31 n=27 m=17 0
▼ ▼ ▼ ▼
mask = 0000 1111 1111 1110 0000 0000 0000 0000
And if we have any 32-bit number, by bitwise OR (|) with this number we can set-1 all bits from m to n. All other bits will be unchanged.
Remember OR works like:
x | 1 = 1 , and
x | 0 = x
where x value can be either 1 or 0.
So by doing:
num32bit = num32bit | mask;
we can set n to m bit 1 and remaining bits will be unchanged. For example, suppose, num32bit = 0011 1001 1000 0000 0111 1001 0010 1101,
then:
0011 1001 1000 0000 0111 1001 0010 1101 <--- num32bit
0000 1111 1111 1110 0000 0000 0000 0000 <--- mask
---------------------------------------- ---------------Bitwise OR operation
0011 1111 1111 1110 0111 1001 0010 1101 <--- new number
---- ▲ ▲ -------------------
|-----------| this bits are from `num32bit`
all bits are
1 here
This is what I mean by:
num32bit = num32bit | mask;
##How to make the mask?
To make a mask in which all bits are 1 from n to m and others are 0, we need three steps:
Create mask_n: All bits on Right side from n=27 are one
BIT NUMBER 31 n=27 0
▼ ▼ ▼
mask_27= 0000 1111 1111 1111 1111 1111 1111 1111
In programming this can be created by right-shift (>>) 4 times.
And, why 4?
4 = 32 - n - 1 ==> 31 - 27 ==> 4
Also note: the complement (~) of 0 has all bits one,
and we need unsigned right shift in C.
Understand the difference between signed and unsigned right shift
Create mask_m: All bits on left side from m=17 are one.
BIT NUMBER 31 m=17 0
▼ ▼ ▼
mask_17 1111 1111 1111 1110 0000 0000 0000 0000
Create mask: Bitwise AND of above to: mask = mask_n & mask_m:
mask = 0000 1111 1111 1110 0000 0000 0000 0000
▲ ▲
BIT NUMBER 27 17
And, below is my getMask(n, m) function that returns a unsigned number that looks like mask in step-3.
#define BYTE 8
typedef char byte; // Bit_sizeof(char) == BYTE
unsigned getMask(unsigned n,
unsigned m){
byte noOfBits = sizeof(unsigned) * BYTE;
unsigned mask_n = ((unsigned)~0u) >> (noOfBits - n - 1),
mask_m = (~0u) << (noOfBits - m),
mask = mask_n & mask_m; // bitwise & of 2 sub masks
return mask;
}
To test my getMask() I have also written a main() function and a binary() function, which prints a given number in binary format.
void binary(unsigned);
int main(){
unsigned num32bit = 964720941u;
unsigned mask = 0u;
unsigned rsult32bit;
int i = 51;
mask = getMask(27, 17);
rsult32bit = num32bit | mask; //set n to m bits 1
printf("\nSize of int is = %ld bits, and "
"Size of unsigned = %ld e.g.\n", sizeof(int) * BYTE,
sizeof(unsigned) * BYTE);
printf("dec= %-4u, bin= ", 21);
binary(21);
printf("\n\n%s %d\n\t ", "num32bit =", num32bit);
binary(num32bit);
printf("mask\t ");
binary(mask);
while(i--) printf("-");
printf("\n\t ");
binary(rsult32bit);
printf("\n");
return EXIT_SUCCESS;
}
void binary(unsigned dec){
int i = 0,
left = sizeof(unsigned) * BYTE - 1;
for(i = 0; left >= 0; left--, i++){
printf("%d", !!(dec & ( 1 << left )));
if(!((i + 1) % 4)) printf(" ");
}
printf("\n");
}
This test code runs like (the output is quite same as I explained in above example):
Output of code:
-----------------
$ gcc b.c
:~$ ./a.out
Size of int is = 32 bits, and Size of unsigned = 32 e.g.
dec= 21 , bin= 0000 0000 0000 0000 0000 0000 0001 0101
num32bit = 964720941
0011 1001 1000 0000 0111 1001 0010 1101
mask 0000 1111 1111 1110 0000 0000 0000 0000
---------------------------------------------------
0011 1111 1111 1110 0111 1001 0010 1101
:~$
Additionally, you can write getMask() function in shorter form in two statements, as follows:
unsigned getMask(unsigned n,
unsigned m){
byte noOfBits = sizeof(unsigned) * BYTE;
return ((unsigned)~0u >> (noOfBits - n - 1)) &
(~0u << (noOfBits -m));
}
Note: I removed redundant parentheses, to clean up the code. Although you never need to remember precedence of operators, as you can override precedence using (), a good programmer always refers to precedence table to write neat code.
A better approach may be to write a macro as below:
#define _NO_OF_BITS sizeof(unsigned) * CHAR_BIT
#define MASK(n, m) (((unsigned)~0u >> (_NO_OF_BITS - n - 1)) & \
(~0u << (_NO_OF_BITS - m)))
And call like:
result32bit = num32bit | MASK(27, 17);
To reset (all zero) bits from n to m
To reset all bits from n to m = 0, and leave the rest unchanged, you just need complement (~) of mask.
mask 0000 1111 1111 1111 1000 0000 0000 0000
~mask 1111 0000 0000 0000 0111 1111 1111 1111 <-- complement
Also instead of | operator to set zero & is required.
remember AND works like:
x & 0 = 0 , and
x & 0 = 0
where x value can be 1 or 0.
Because we already have a bitwise complement ~ operator and and & operator, we just need to do:
rsult32bit = num32bit & ~MASK(27, 17);
And it will work like:
num32bit = 964720941
0011 1001 1000 0000 0111 1001 0010 1101
mask 1111 0000 0000 0000 0111 1111 1111 1111
---------------------------------------------------
0011 0000 0000 0000 0111 1001 0010 1101

Resources