0

I want to understand how does the microcontroller determine that the conditions provided to it in the input are true or false. eg:

if (someVariable > 50)
{
 // do something here
}

Then how does Arduino determine if the value that I put in `somevariable' is larger than 50 (as apposed to less than or equal to 50)?

sa_leinad
3,2182 gold badges23 silver badges51 bronze badges
asked Nov 30, 2016 at 12:54
1
  • It's not clear to me what you are asking. Could you find another way to phrase it, please? Do you want to know what machine instructions it uses to evaluate (someVariable > 50)? Or something else? Commented Nov 30, 2016 at 13:03

2 Answers 2

7

In general terms comparisons are usually performed, at the low level of assembly language, using subtraction.

In assembly language when you perform a subtraction there are flags in the status register that may or may not get set depending on what has happened. These include the Zero flag and the Carry flag.

If you are comparing A to B then you subtract B from A and see what happened by examining the flags.

For instance, if your variable contains 30 and you compare it to 50 you subtract 50 from 30. Because the result "passes through" zero the Carry flag is set. You can then do a "Jump if Carry Set" call.

If you should have 50 in your variable and you compare it to 50 the subtraction ends up with the Zero flag set since the result is exactly zero. It is then possible to do a "Jump if Zero Set" call.

If you have 60 in your variable and compare it to 50, the subtraction results in 10, which doesn't set either flag. That is actually slightly harder to work out (depending on architecture) since you are then wanting to compare two flags (Carry and Zero) and see if neither of them are set. So it is common for the compiler to optimize it so that the condition is reversed (a > b is the same as !(a <= b) for instance).

Of course, some architectures have actual comparison instructions (often CMP) which compares two registers and sets or clears the different flags for you. For instance, the ATMega328P has the instructions:

  • CPSE - Compare, Skip if Equal
  • CP - Compare
  • CPC - Compare with Carry
  • CPI - Compare Register with Immediate

CPI would be the most logical choice in the example you give - compare the contents of a register (variable) with an "immediate" value (an "immediate" value is a constant value):

CPI $r3, 50

According to the instruction set manual the comparison is, surprise surprise, performed as a subtraction, and what happened during the subtraction sets the different flags. To make life simpler the instruction set has a number of branch instructions which look at the different flag combinations and jump to another address if they match:

  • BRLT - Branch if the result of the previous comparison was A < B
  • BRLE - Branch if the result of the previous comparison was A <= B
  • BRGT - Branch if the result of the previous comparison was A> B
  • BRGE - Branch if the result of the previous comparison was A>= B
  • BREQ - Branch if the result of the previous comparison was A == B
  • BRNE - Branch if the result of the previous comparison was A != B

There are more as well for other special comparisons. You can read up all about them in the AVR instruction set manual.

answered Nov 30, 2016 at 13:27
5

Just to complement Majenko's answer with an example, I tried the following:

volatile int someVariable;
void do_something_here();
void foo()
{
 if (someVariable > 50)
 {
 do_something_here();
 }
}

and the compiler generated the following assembly (comments mine):

foo:
 lds r24, someVariable ; load variable into registers, LSB
 lds r25, someVariable + 1 ; and MSB
 sbiw r24, 51 ; subtract 51
 brlt .L1 ; if (result < 0) goto .L1
 jmp do_something_here ; do_something_here()
.L1:
 ret ; return

The sbiw instruction means "subtract immediate from word". It subtracts a 6-bit immediate value from a 16-bit value contained in a register pair (r25:r24 in this case). It is one of the very few 16-bit instructions of this mostly 8-bit CPU.

As you see, the compiler did some optimization and changed the code to something looking more like:

if (!(someVariable - 51 < 0))
{
 do_something_here();
}

It is also worth noting that the brlt instruction (branch if lower than) tests the sign flag of the status register, which is the exclusive OR of the negative flag (result < 0) and the overflow flag. This way the result of the comparison is correct even if the subtraction overflows.

Note also that this is only an example. The generated assembly would be different if you use another type than int (a wider or smaller or unsigned integer), or an explicit constant greater than 62.

answered Nov 30, 2016 at 14:39

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.