I've seen assignment operators, notably more common in µC code, that use " |= ". I assume this is a bitwise OR assignment, much like a += or a *=.
I can see the use of it if you intend to use it as a bitwise function (such as here: http://imakeprojects.com/Projects/avr-tutorial/ ), but have also seen it used as an initial assignment (such as here: http://fourwalledcubicle.com/files/Chaser.c ). Why use it as an initial assignement? Isn't that just more work for the chip (checking both bytes and setting the OR value versus just setting a known value)? Is there any particular advantage?
I think I've seen it other places too, but I can't really google for what it sees as punctuation.
Why the bitwise or assignment?
Moderators: adafruit_support_bill, adafruit
Please be positive and constructive with your questions and comments.
-
- Posts: 373
- Joined: Tue Mar 06, 2007 11:51 pm
Re: Why the bitwise or assignment?
Coding clarity. Using the bitwise OR, you can see what is going on much easier than a direct assignment. Typically, I see it used for initializing register bits to 1.
So, say register reg_x controls the settings of function y, and upon microcontroller startup, it is guaranteed to have value 0x00. To get the functionality you want, the register needs to hold the value 0x33 (0b00110011). While is certainly valid, that tells you nothing about what those bits in reg_x do. Now, if you use a bitwise or, such as:
You can see that, though they are in acronym form, the names of the bits seem a little more informative. Rather than a series of 1's and 0's, those digits now have names. If you really wanted to be robust in your commenting, you could cover all 8 bits, like:
And know what the register does and is set to in a much simpler way than just assigning 0x33. Also, with the OR method, you no longer need to worry about if you have the right bit for the feature you want to enable, you just need to know the acronym.
edit:
What formerly inhabited this area was proved wrong, see my post below. Thanks for the catch oPossum
So, say register reg_x controls the settings of function y, and upon microcontroller startup, it is guaranteed to have value 0x00. To get the functionality you want, the register needs to hold the value 0x33 (0b00110011). While
Code: Select all
reg_x = 0x33;
Code: Select all
reg_x |= (1 << MUX2) | (1 << MUX1) | (1 << LALN) | (1 << EN);
Code: Select all
reg_x |= (0 << MUX4) | (0 << MUX5) | (1 << MUX2) | (1 << MUX1) | (0 << MUX0) | (0 << (ACT)| (1 << LALN) | (1 << EN);
edit:
What formerly inhabited this area was proved wrong, see my post below. Thanks for the catch oPossum
Last edited by The_Don125 on Fri Apr 03, 2009 3:42 am, edited 3 times in total.
-
- Posts: 4
- Joined: Thu Mar 05, 2009 11:42 am
Re: Why the bitwise or assignment?
Ok, awesome about it actually taking less time, now I have a tangible reason to use it.
Maybe someday I'll switch over to the way you coded it, but to me, it's easier to read the ones and zeroes with a comment line over it.
It does make sense, though, the way you wrote that.
Maybe someday I'll switch over to the way you coded it, but to me, it's easier to read the ones and zeroes with a comment line over it.
It does make sense, though, the way you wrote that.
- opossum
- Posts: 636
- Joined: Fri Oct 26, 2007 12:42 am
Re: Why the bitwise or assignment?
For what microcontroller?The_Don125 wrote:A direct register assignment of an 8-bit variable takes 2 cycles to complete, while using OR to turn on the bits you want and leaving the remainder unchanged only needs a single clock cycle.
The LDI (Load Immediate) and ORI (Logical OR with Immediate) are both one word single cycle AVR instructions.
-
- Posts: 373
- Joined: Tue Mar 06, 2007 11:51 pm
Re: Why the bitwise or assignment?
Ah, my mistake, looks like I read the data for LDS rather than LDI
And, in the interest of complete testing (actually procrastinating homework), I decided to see how the two tasks compile using AVR-GCC, Optimization level 3
Looks like I was way off. Not only is LDI only one clock cycle, but removing the OR actually removes an instruction from the compiled code!
Now to try optimization level s (I already tried optimizations 0 and 1, both of those need about 10 assembly instructions to do what was accomplished above in 3-4)
Same result. Optimization level 2 also gives the same assembly instructions.
And, in the interest of complete testing (actually procrastinating homework), I decided to see how the two tasks compile using AVR-GCC, Optimization level 3
Code: Select all
PORTB |= 0x33;
52: 88 b3 in r24, 0x18 ; 24 one clock
54: 83 63 ori r24, 0x33 ; 51 one clock
56: 88 bb out 0x18, r24 ; 24 one clock
58: ff cf rjmp .-2 ; 0x58 <main+0x6> two clocks
PORTB = 0x33;
52: 83 e3 ldi r24, 0x33 ; 51 one clock
54: 88 bb out 0x18, r24 ; 24 one clock
56: ff cf rjmp .-2 ; 0x56 <main+0x4> two clocks
Now to try optimization level s (I already tried optimizations 0 and 1, both of those need about 10 assembly instructions to do what was accomplished above in 3-4)
Code: Select all
PORTB |= 0x33;
52: 88 b3 in r24, 0x18 ; 24
54: 83 63 ori r24, 0x33 ; 51
56: 88 bb out 0x18, r24 ; 24
58: ff cf rjmp .-2 ; 0x58 <main+0x6>
PORTB = 0x33;
52: 83 e3 ldi r24, 0x33 ; 51
54: 88 bb out 0x18, r24 ; 24
56: ff cf rjmp .-2 ; 0x56 <main+0x4>
- opossum
- Posts: 636
- Joined: Fri Oct 26, 2007 12:42 am
Re: Why the bitwise or assignment?
Try it with a variable (uint8_t) rather than a port. The code will be different. The AVR is non-orthogonal in a rather annoying way (if you are writing asm code at least).
-
- Posts: 373
- Joined: Tue Mar 06, 2007 11:51 pm
Re: Why the bitwise or assignment?
Well, using this code:
Everything involving val got optimized into oblivion if I used any optimization level other than 0. I can see why though, it doesn't actually do anything.
Fixing the code so that it doesn't disappear, I now get the following at optimization 1 - s:
So they in fact compile down to the exact same assembly.
The code used was:
Code: Select all
#include <avr/io.h>
int main(void)
{
uint8_t val;
val = 0x33;
val = val + 1;
while(1);
}
Fixing the code so that it doesn't disappear, I now get the following at optimization 1 - s:
Code: Select all
uint8_t val;
val |= 0x33;
52: 83 e3 ldi r24, 0x33 ; 51
PORTB = val;
54: 88 bb out 0x18, r24 ; 24
56: ff cf rjmp .-2 ; 0x56 <main+0x4>
uint8_t val;
val = 0x33;
PORTB = val;
52: 83 e3 ldi r24, 0x33 ; 51
54: 88 bb out 0x18, r24 ; 24
56: ff cf rjmp .-2 ; 0x56 <main+0x4>
The code used was:
Code: Select all
#include <avr/io.h>
int main(void)
{
uint8_t val;
val = 0x33;
PORTB = val;
while(1);
}
- opossum
- Posts: 636
- Joined: Fri Oct 26, 2007 12:42 am
Re: Why the bitwise or assignment?
A more realistic example.
Code: Select all
#include <stdint.h>
main()
{
volatile uint8_t x[601];
x[0]=1;
x[100]=2;
x[200]=3;
x[300]=4;
x[400]=5;
x[500]=6;
x[600]=7;
x[0]|=8;
x[100]|=9;
x[200]&=10;
x[300]&=11;
x[400]|=12;
x[500]|=15;
x[600]&=16;
}
Last edited by opossum on Fri Apr 03, 2009 5:55 am, edited 2 times in total.
- opossum
- Posts: 636
- Joined: Fri Oct 26, 2007 12:42 am
Re: Why the bitwise or assignment?
Ports must be declared volatile for code to work as expected. val was optimized away because it was not declared volatile.The_Don125 wrote:Everything involving val got optimized into oblivion if I used any optimization level other than 0. I can see why though, it doesn't actually do anything.
If the code is simple enough to keep all variables in registers, then the non-orthogonal nature will not show. A program of any significant complexity will force variables into RAM and the code for variables will then be different than for ports.
- westfw
- Posts: 2010
- Joined: Fri Apr 27, 2007 1:01 pm
Re: Why the bitwise or assignment?
This doesn't explain why you wouldn't just do:And know what the register does and is set to in a much simpler way than just assigning 0x33. Also, with the OR method, you no longer need to worry about if you have the right bit for the feature you want to enable, you just need to know the acronym.Code: Select all
reg_x |= (0 << MUX4) | (0 << MUX5) | (1 << MUX2) | (1 << MUX1) | (0 << MUX0) | (0 << (ACT)| (1 << LALN) | (1 << EN);
Code: Select all
reg_x = (0 << MUX4) | (0 << MUX5) | (1 << MUX2) | (1 << MUX1) | (0 << MUX0) | (0 << (ACT)| (1 << LALN) | (1 << EN);
However, in may cases, a key thing to understand is that it's NOT necessarily an initial assignment when you're dealing with an IO register in a microcontroller. There may be other bits in the register that have other functions that you do not want to interfere with. So doing something like:
Code: Select all
ADCSRA |= 1<<ADSC;
Please be positive and constructive with your questions and comments.