4.2.1. Bitwise operators
4.2.1.1 bit and&
(1) Note: the bit and symbol are one &, and the two & & are logical and.
(2) Truth table: 1 & 0 = 0 1 & 1 = 1 0 & 0 = 0 0 & 1 = 0
(3) It can be seen from the truth table that the characteristic of bit and operation is that only 1 and 1 are located, and the result is 1, and the rest are all 0
(4) The difference between bit and logical and: bit and time operands are summed according to the corresponding phase of the binary bit, and logical and is the sum of the two operands as a whole. (for example: 0XAA & 0xf0 = 0xa0, 0XAA & & 0xf0 = 1)
4.2.1.2 bit or|
(1) Note: bit or symbol is one 𞓜 and two | are logical or.
(2) Truth table: 1|0 = 1 1|1 = 1 0|0 = 0 0|1 = 1
(3) It can be seen from the truth table that the characteristic of bit or operation is that only two 0 phases or can get 0. As long as there is one 1, the result must be 1
(4) The difference between bit or and logical or: when bit or, the two operands are connected according to the corresponding phase of the binary bit, and the logical or two operands are connected as a whole.
4.2.1.3 reverse bit~
(1) Note: the median negation in C language is ~, and the logic negation in C language is!
(2) Bitwise inversion is to reverse the binary bits of operands one by one (1 becomes 0, 0 becomes 1); The logic negation is true (in C language, any number that is not 0 is true) becomes false (in C language, only 0 means false), and false becomes true.
Experiment: if any non-zero number is logically negated and then negated, it will get 1; Any number of times that is not 0 is inversed by bit and then inversed, and he will get himself; #include <stdio.h> int main(void) { /* * 45:101101 * 23:010111 * 58:111010 ^operation */ // Bit exclusive or unsigned int a = 45, b = 23; unsigned int c; c = a ^ b; // 58 printf("c = %d.\n", c); /* // Bitwise and logical negation and then negation unsigned int a = 45; unsigned int b, c; b = ~~a; // Reverse by bit, operate bit by bit, 1 becomes 0, 0 becomes 1 c = !!a; // Take the opposite according to logic, true becomes false, and false becomes true printf("b = %u.\n", b); printf("c = %d.\n", c); */ /* // Bitwise and logical negation unsigned int a = 45; unsigned int b, c; b = ~a; // Reverse by bit, operate bit by bit, 1 becomes 0, 0 becomes 1 c = !a; // Take the opposite according to logic, true becomes false, and false becomes true printf("b = %u.\n", b); printf("c = %d.\n", c); */ return 0; }
4.2.1.4 bit exclusive or^
(1) Bit exclusive or truth table: 1 ^ 1 = 0 0 ^ 0 = 0 1 ^ 0 = 1 0 ^ 1 = 1
(2) Characteristics of bit exclusive or: if two numbers are equal, the result is 0 and the unequal result is 1. Memory method: XOR is to operate on the difference.
Summary of the characteristics of bit and, bit or and bit XOR:
Bit and: (any number, in fact, is 1 or 0) with 1 and no change, with 0 and becomes 0
Bit or: (any number, actually 1 or 0) with 1 bit or becomes 1, with 0 bit or no change
Bit exclusive or: (any number, in fact, is 1 or 0) the exclusive or with 1 will be reversed, and the exclusive or with 0 will not change
4.2.1.5 left shift < < and right shift > >
The shift of C language depends on the data type.
For unsigned numbers, 0 is added to the right when shifting left (equivalent to logical shift)
For unsigned numbers, 0 is added to the left when moving to the right (equivalent to logical shift)
For signed numbers, 0 is added to the right when shifting left (called arithmetic shift, equivalent to logical shift)
For signed numbers, when moving right, the left side is filled with sign bits (if positive numbers are filled with 0 and negative numbers are filled with 1, it is called arithmetic shift)
**
4.2.2. The special function of bit and bit or bit exclusive or in operating registers
4.2.2.1 requirements for register operation (special position change without affecting other bits)**
(1)ARM is uniformly addressed by memory and IO. There are many internal peripherals in ARM. The CPU in SoC controls the internal peripherals by writing some specific values to the registers of these internal peripherals, and then controls the hardware action. Therefore, it can be said that reading and writing registers is to control the hardware.
(2) The register is characterized by bit planning and use. However, the reading and writing of the register is carried out together with the whole 32 bits (that is, you can't just modify bit5 ~ bit7, but you must write all 32bit s as a whole)
(3) The requirement of register operation is that other bits cannot be affected when setting a special position.
(4) How? The answer is: read change write trilogy. The operation concept of read rewrite is: when I want to change some special positions in a register, I won't write it directly. I will first read the original value of the whole register, then modify the special position I want to modify on this basis, and then write the modified value into the register as a whole. The effect of this is that the value of the bit I care about has been modified without affecting the original value of other bits.
4.2.2.2 special positioning and zero clearing&
(1) Review the characteristics of bit and operation mentioned in the previous section: (any number is actually 1 or 0) with 1 bit and no change, with 0 bit and become 0
(2) If you want to change some special positions of a register into 0 without affecting other bits, you can construct an appropriate number composed of 1 and 0 and operate with the original value of the register, and then you can clear the special position.
(3) For example: suppose the value in the original 32-bit register is 0xaaaaaa, we want to clear bit8 ~ bit15 while other bits remain unchanged. We can sum this number with 0xFFFF00FF.
4.2.2.3 specific location 1|
(1) Review the characteristics of bit or operation mentioned in the previous section: any number, in fact, is 1 or 0) and 1 bit or become 1, and 0 bit or no change
(2) The operation method is similar to that just mentioned. We want to construct such a number: set the specific bit of 1 to 1 and the other bits to 0, and then compare this number with the original number.
4.2.2.4 reverse use of special positioning^
(1) Review the characteristics of bit XOR operation mentioned in the previous section: (any number, in fact, is 1 or 0) the XOR with 1 will be reversed, and the XOR with 0 will not change
(2) The operation method is similar to that just mentioned. We want to construct such a number: the specific bit to be reversed is 1 and the other bits are 0, and then we can XOR this number with the original number.
Experiment: special positioning operation #include <stdio.h> int main(void) { /* // Invert bit4 ~ bit7 of a register value, and the other bits remain unchanged unsigned int a = 0x123d0c37; unsigned int b = 0xf0; unsigned int c; c = a ^ b; printf("a & b = 0x%x.\n", c); */ /* // Set bit4 ~ bit7 of a register value to 1, and the other bits remain unchanged unsigned int a = 0x123d0cd7; unsigned int b = 0xf0; unsigned int c; c = a | b; printf("a & b = 0x%x.\n", c); */ /* // Clear bit13 ~ 21 of a register value to 0, and other bits remain unchanged unsigned int a = 0x123d0c57; unsigned int b = 0xffc01fff; unsigned int c; c = a & b; printf("a & b = 0x%x.\n", c); // 0xaaaa00aa */ /* unsigned int a = 0x12aaaaa7; unsigned int b = 0xFFFF00FF; unsigned int c; c = a & b; printf("a & b = 0x%x.\n", c); // 0xaaaa00aa */ }
4.2.3. How to construct a specific binary number with bit operation
4.2.3.1 register bit operation often needs to be specially located to a specific value
(1) As can be seen from the previous section, the key difficulty in setting 1 or clearing 0 or reversing the special location of the register is to construct a special number in advance. This number and the original value can be operated by bit and, bit or, bit XOR and other operations, so as to meet our requirements for register operation.
(2) Solution 1: use tool software or calculator or your own brain to calculate and directly give a complete 32-bit specific number.
Advantages: it can complete the work, is not difficult, and the operation is not too troublesome.
Disadvantages: it depends on tools and is not intuitive. It is not easy for people who read the program to understand.
Evaluation: it can be used, but it is not easy to use. It should be replaced by a better method.
(2) Solution 2: write your own code and use bit operation symbols (mainly shift and bit inversion) to construct this specific binary number
4.2.3.2 use shift to obtain binary number with special position of 1
(1) The simplest is to use shift to obtain a binary number with a specific position of 1. For example, we need a binary number with bit3 ~ bit7 as 1 (implying that all other bits are 0), which can be as follows: (0x1f < < 3)
(2) More difficult requirements: obtain the number of bit3 ~ bit7 as 1, bit23 ~ bit25 as 1, and the rest bits as 0: ((0x1f < < 3) | (7 < < 23))
4.2.3.3. Reverse the combination bit to obtain a binary number with a special position of 0
(1) This time, we need to get the number with bit4 ~ bit10 as 0 and all the other bits as 1. How do you do it?
(2) Using the above method: (0xf < < 0) | (0x1ffff < < 11)
But the problem is: there are too many consecutive digits of 1, which is difficult to construct, so the advantage of this method is lost.
(3) This kind of special position (less) is 0 and the other bits (most) are 1. It is not suitable to be constructed by many continuous 1 shifts to the left, and it is suitable to be constructed by left shifts plus bit negation.
(2) The idea is: first try to construct the phase inverse of this number, and then take the inverse to get this number. (for example, in this example, the number bit4 ~ bit10 to be constructed is 0, and the other bits are 1. Let's construct a number bit4 ~ bit10 is 1, and the other bits are 0, and then reverse the number by bits)
4.2.3.4 summary: bits and, bits or combined with specific binary numbers can complete the operation requirements of register bits
(1) If the number you want is relatively small, the bit is 1, and most bits are 0, you can get it by shifting n bits to the left of many consecutive ones.
(2) If the number you want is relatively few, the bits are 0 and most of the bits are 1, you can get it by constructing its bit inverse first and then taking the bit inverse.
(3) If you want more than one continuous 1 (continuous 0) part of the number, you can construct it separately through multiple segments, and then bit and with each other. At this time, because the bits with the number of 1 participating in the bit or operation are not repeated, the bits at this time are actually equivalent to the superposition of several numbers.
Practice: actual shift operation
#include <stdio.h> #define VALUE1 937 #define VALUE2 17 int main(void) { a |= ((VALUE1<<7) | (VALUE2<<21)); /* // The second solution unsigned int a = 0xc30288f8; a &= ~((0x3ff<<7) | (0x1f<<21)); // bit7~bit17 And bit21 ~ bit25 are all cleared a |= ((937<<7) | (17<<21)); // 937 And 17 all assignments printf("a = 0x%x.\n", a); // 0xc223d4f8 */ /* // The first solution: direct double question 6. unsigned int a = 0xc30288f8; // bit7~bit17 Assignment 937 a &= ~(0x3ff<<7); // bit7~ bit17 Clear a |= 937<<7; // bit21~bit25 Assignment 17 a &= ~(0x1f<<21); // bit21~bit25 Clear a |= 17<<21; printf("a = 0x%x.\n", a); // 0xc223d4f8 */ /* unsigned int a = 0xc30288f8; // 0xc34648f8 //The first step is to read out the original bit7 ~ bit17 values unsigned int tmp = 0; tmp = a & (0x3ff<<7); //printf("befor shift, tmp = 0x%x.\n", tmp); tmp >>= 7; // The ghost is here. //printf("after shift, tmp = 0x%x.\n", tmp); //The second step is to add 17 to this value tmp += 0; //Step 3: clear bit7 ~ bit17 of a a &= ~(0x3ff<<7); //The fourth step is to write the value calculated in the second step into bit7 ~ bit17 a |= tmp<<7; printf("a = 0x%x.\n", a); */ /* unsigned int a = 0xc30288f8; // The first step is to clear bit7 ~ bit17 a &= ~(0x7ff<<7); // The second step is to assign 937 to bit17 a |= (937<<7); printf("a = 0x%x.\n", a); */ /* unsigned int a = 0xc30288f8; // The first step is to keep the bits from bit3 to bit8 unchanged and clear all the other bits a &= (0x3f<<3); // The second step is to shift it to the right by 3 bits printf("a = 0x%x.\n", a); a >>= 3; printf("a = %u.\n", a); */ /* unsigned int a; a = 0xFFFFFFFF; a &= (~(0x1ff<<15)); printf("a = 0x%x.\n", a); */ /* unsigned int a; a = 0xFFFFFFFF; a &= (~(1<<15)); printf("a = 0x%x.\n", a); */ /* unsigned int a; a = 0; a |= (0b11111<<3); // bit3 At the beginning, there are five consecutive bits, that is, bit3 ~ bit7 printf("a = 0x%x.\n", a); */ return 0; }
4.2.4. Bit operation practice 1
Review: to set 1 to use |, use clear to use &, use reverse ^, ~ and < > > to build specific binary numbers.
4.2.4.1. Given an integer a, set bit3 of a to ensure that other bits remain unchanged.
A = a | (1 < < 3) or a | = (1 < < 3)
4.2.4.2. Given an integer a, set bit3~bit7 of a and keep other bits unchanged.
A = a | (0b11111 < < 3) or a | = (0x1f < < 3);
4.2.4.3. Given an integer a, clear bit15 of a to ensure that other bits remain unchanged.
a = a & (~(1<<15)); Or a & = (~ (1 < < 15));
4.2.4.4. Given an integer a, clear bit15~bit23 of a and keep other bits unchanged.
a = a & (~(0x1ff<<15)); Or a & = (~ (0x1ff < < 15));
4.2.4.5. Given an integer a, take out bit3~bit8 of A.
Idea:
Step 1: first, keep the number bit3 ~ bit8 unchanged, and clear all the other bits.
The second step is to shift it to the right by 3 bits to get the result.
The third step is to figure out the above two-step algorithm, and then turn it into C language.
a &= (0x3f<<3);
a >>= 3;
4.2.4.6 assign 937 values to bit7 ~ bit17 of a register in C language (other bits are not affected).
Key points: first, other bits cannot be affected; Second, you don't know the value of the original bit7 ~ bit17.
Idea: the first step is to clear all bit7 ~ bit17. Of course, other bits cannot be affected.
The second step is to write 937 into bit7 ~ bit17. Of course, other bits cannot be affected.
a &= ~(0x7ff<<7);
a |= (937<<7);
4.2.5. Bit operation practice 2
4.2.4.7 add 17 to the values in bit7 ~ bit17 of a register in C language (the other bits are not affected).
Key point: I don't know the original value Idea: the first step is to read out the original bit7~bit17 Value of The second step is to add 17 to this value The third step is to bit7~bit17 Clear Step 4: write the value calculated in step 2 into bit7~bit17
4.2.4.8 assign 937 values to bit7 ~ bit17 of a register in C language, and assign 17 values to bit21 ~ bit25 at the same time
Idea: the upgraded version of 4.2.4.6 can be solved by twice the code in 4.2.4.6.
Analysis: This is OK, but the effect is not high enough. We have a better solution, which is to combine two steps into one step.
4.2.6. Technology upgrade: complete bit operation with macro definition
4.2.6.1 directly use macro to set and reset (the rightmost is the first bit).
// Question 1: use the macro definition to set the nth bit of 32-bit x (from the right, that is, bit0 is the first bit) #define SET_BIT_N(x, n) (x | (1U<<(n-1))) // Question 2: use the macro definition to clear the nth bit of 32-bit x (from the right, that is, bit0 is the first bit) #define CLEAR_BIT_N(x, n) (x & ~(1U<<(n-1))) // Question 3: use the macro definition to set the nth to m bits of 32-bit x (from the right, that is, bit0 is the first bit, and M is the high bit) // Analysis: add n=3 and m=6. The problem is to set bit2 to bit5 // We need a formula to get (m-n+1) 1 // Algorithm: Step 1: get 32 bits first ~ 0U // Step 2: move the number obtained in step 1 to the right by x bits to obtain (m-n + 1) 1 (~0U)>>(32-(m-n+1)) #define SET_BIT_N_M(x, n, m) (x | (((~0U)>>(32-(m-n+1)))<<(n-1)))
//Question 4: intercept some continuous bits of variables. For example: variable 0 x88, That is, 1000 b,If section 2 is intercepted~4 Bit, then the value is: 100 b = 4 #define GETBITS(x, n, m) ((x & ~(~(0U)<<(m-n+1))<<(n-1)) >> (n-1)) Analysis: this topic is equivalent to our 4.2.4.5 The only thing to do in is to use macros. So this topic is quite important x of bit(n-1)reach bit(m-1)take out How to analyze complex macros: ((x & ~(~(0U)<<(m-n+1))<<(n-1)) >> (n-1)) The first step is to make clear that this complex macro is divided into several parts: 2 parts (x & ~(~(0U)<<(m-n+1))<<(n-1)) >> (n-1) Analyze why>>(n-1),So we 4.2.4.5 The second step in The second step is to continue to analyze the rest: it is divided into two parts x & ~(~(0U)<<(m-n+1))<<(n-1) Analyze why&,Equivalent to us 4.2.4.5 The first step in Step 3: continue to analyze the remaining: ~ (~(0U)<<(m-n+1)) << (n-1) In this analysis, it is necessary to find out whether the second lump should be taken from the left and then from the right<<Or right first<<Take the opposite on the left. Solution: first, check C Language priority table; Second, write a code test yourself. It shows that this formula should be ~(~(0U)<<(m-n+1)) << (n-1) ,This is divided into two parts 10001000 00001110 00001000
Exercise: code testing ~ and < < who has the highest priority
int main(void) { // Write code test ~ and < < whose priority is high unsigned int a = 0xf; unsigned int b = 0; b = ~a<<4; // If the first ~ result is 0xffff00 If first < < the result is: 0xffff0f printf("b = 0x%x.\n", b); // The result is 0xffff00, indicating that ~ priority is high /* unsigned int a = 0x0; unsigned int b = 0; b = SET_BIT_N_M(a, 5, 8); printf("b = 0x%x.\n", b); */ /* // test for CLEAR_BIT_N unsigned int a = 0xFFFFFFFF; unsigned int b = 0; b = CLEAR_BIT_N(a, 4); printf("b = 0x%x.\n", b); */ /* // test for SET_BIT_N unsigned int a = 0; unsigned int b = 0; b = SET_BIT_N(a, 4); printf("b = 0x%x.\n", b); */ return 0; }