simple branch/compare question

Go To Last Post
20 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

here is a simple predicament that seems to have me temporarily baffled due to a lack of sleep. My program was acting up & I found a simple branch might be the problem.

say temp=r18 contains 33 hex. I want to add 20 hex to this value & and branch whenever volts=r19 is less than this sum:

ldi temp, data ;get the value
subi temp, $E0 ; "ADD" 20
cp volts, temp
brlo do_it ;volts<= temp+20

This seems to work, but if temp is, say $F3, then adding $20 gives $13. Then a value such as $F5 will not be "lower" than the sum as intended. Essentially the rollover will screw everything up. I can program a workaround with a lot of tests & manipulations--but is there a simple wayto avoid these types of rollover problems?

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just off the top of my head, how's this for an approach?


;; IS volts < (data + 0x20)?
;; R18 has data
;; R19 has volts
;; R17 working reg

R17 = R19 - R18
IF (R17 < 0x20)
    BRANCH       ;; yes, volts < (data + 0x20)
ELSE
    RETURN?
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

@Zoom: Won't that suffer from the same rollover problem if volts is less than 20?

Can we assume that volts is never higher than $FF? If you go with a ldi, add sequence instead of the single subi the carrry flag will indicate if a rollover has occured. In that case temp+20 is definitively greater than $FF, and volts<=temp+20 is definitively not true. This will cost you one more temporry register, and a few instructions extra.

Btw: Predicament is a wonderful word! I seem to recall an early Donald Duck cartoon where Donald, just before falling off the cliff or some such, looks at the audience and goes "What a predicament!". Priceless.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hey, here's a sample assembly source you can assemble in AVR Studio and execute with the simulator. I tried all of the corner cases and I think this will do what you are looking for fairly efficiently. NOTE: register r19 is modified.

; A wee test program
;
; If volts < (test - $20) branch to :good
; If volts >= (test - $20) branch to :nogo
;
.org    $0
    rjmp    start

start:

; Initialize registers with test values
; for data (r18) and volts (r19)
;
    ldi     r18,$0      ; data (change immediate values to verify)
    ldi     r19,$f0     ; volts

    sbc     r19, r18    ; volts - data
    brcs    good
    cpi     r19,$20
    brlo    good

nogo:
    rjmp    nogo        ; volts >= (data + $20)

good:
    rjmp    good        ; volts < (data + $20)

EDIT 1: Made all of the prefixes for hex constants the same.
EDIT 2: Fixed the comment about which register was for volts.

Last Edited: Mon. Jul 17, 2006 - 12:02 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In addition to testing with the brlo, you can also test the carry bit for a rollover.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

OK, I can do anything in ARM assembly language, but I've used nothing but C on the AVR so far. I had to poke around the AVR instruction set quite a bit to come up with the above code. :shock:

Quote:
In addition to testing with the brlo, you can also test the carry bit for a rollover.

@dksmall: Would you please provide a sample?
@johan: Sample please?

Tom

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

OK, so take your favourite C compiler and code up

if (volts < (test - 0x20))
    {
    frog = 0;
    }
else
   {
   frog = 1;
   }

and look at the resulting machine language sequence generated. Make those highly-paid compiler writers earn their salaries.

It would be a good starting point. Often, I'll look at a sequence and say WTF. Then, after digesting it I realize what a clever method it was.

Declare test & volts with the width and "signness" as you want the ASM op to do; also register or not.

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Good idea, Lee. Here's what winavr produces:

with unsigned char test, volts;
A bit wordy, but it works!

Tom

Last Edited: Mon. Jul 17, 2006 - 01:01 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You can test the carry bit with instructions like brcc and brcs.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
You can test the carry bit with instructions like brcc and brcs.

I did! I did! I did do that!

What I couldn't figure out how to do was to come up with a conditional branch that would work with the cpi directly following the sbc, with out the intermediate brcs good conditional branch.

Tom

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hmmm, the widening to int sure made it pretty ugly. Maybe that better takes care of the overflow/wrap case. But the key point is the BRGE/BRLT (signed) vs. the BRLO/BRSH (unsigned) that have been mentioned so far in the thread IIRC, right?

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You can also consider the arrangement of your expressions:

For instance if volts + 20 will never result in an overflow you could do something like:

if temp < ( volts + 0x20 )

ldi temp, data
subi volts, -0x20
cp temp, volts
brlo do_it

Mike H.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I guess I'm late to the party. I saw the other thread first, and put my response there. https://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=40341
That'll teach me to read avrfreaks posts in forward chronological order.

dksmall wrote:
You can test the carry bit with instructions like brcc and brcs.

brlo is an alias for the brcs. And likewise, brsh is an alias for brcc. The aliases perform the same operations, but can add a little bit of self-documentation to your code.

Edit: after re-reading the thread, I guess you knew that. I only quickly scanned this thread, since I had already posted to the other one.

--Brian

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I would do it using a high register pair like r24/r25, X, Y or Z. First SER the high register (set it to 0xFF), then ADIW the 0x20 to the pair. No ambiguity now - if the addition carries, you can BRCS out of the path right there, otherwise you can be confident the CP will work as you expect.

      ldi     r24,data
      ser     r25
      adiw    r24,0x20
      brcs    do_it
      cp      volts,r24
      brcs    do_it

edit: Looks like I had my logic backwards there. Down the memory hole with it; silence, Winston Smith.

Last Edited: Mon. Jul 17, 2006 - 03:52 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

peret, do you really need the 16bit adiw?

Isn't this equivalent? (and 1 cycle faster) :

      ldi     r24, data
      ldi     r25, 0x20
      add     r24, r25
      brcs    dont_do_it
      cp      volts,r24
      brcs    do_it
dont_do_it: 

--Brian

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Some questions:

(1) Are we assuming that volts, data, and temp are all unsigned 8-bit?
(2) If yes, how should volts=$ff and data = $f0 be handled? Should data always be extended to a unsigned 16-bit if (data + $20) overflows 8-bits? If yes, do agree that in this case, $ff < ($f0 + $20) is TRUE??

If yes to all of the above questions, then
@bcb: your solution fails when data > $df, regardless of volts value.
@peret: your solution also fails then data > $df, regardless of volts value.
@zoom: your solution works for all cases.

If no to any of these questions, then what are the correct assumptions?

Quote:
This seems to work, but if temp is, say $F3, then adding $20 gives $13. Then a value such as $F5 will not be "lower" than the sum as intended.

From what I can tell of avrcandies original post (quote above) , the answers to the above questions are all yes.

@avrcandies: Would you please tell us more about the application? Why do you subtract $20 from data before comparing with volts? I feel like we're in a little black box here. I need to get a life.

Tom

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

zoomcityzoom wrote:
@zoom: your solution works for all cases.

Did you just congratulate yourself? :P

Anyways.. In my haste to mod peret's code, what I thought that i had written, and what I had actually wrote were two seperate things.

This is what I had intended:

      ldi     r24, data
      ldi     r25, $20
      add     r24, r25
      brcs    do_it	          ;If data+$20 overflows, do_it
      cp      volts,r24
      brcs    do_it             ;If volts < data+$20, do_it

"doing it" is assumed if data>$DF.

This is one solution among many possibilities, but a final solution can't be found without more input from avrcandies.

--Brian

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Did you just congratulate yourself? Razz

Yes, I did. And then I laughed and laughed with childish joy! :lol:

Well, there you go. Your routine passes all of my tests that define what I know at this point. Beautiful!

Tom

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hmmm, do we seem a bit overbearing in our responses? I couldn't imagine walking into a conference room with 10 AVRfreaks for a (hardware or firmware) design review :shock:

Tom

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

@bcb, yes, of course I didn't need the ADIW in this case; I was so fixated on extending the addition to 16 bits that I overlooked the obvious.