Learing the wonderful art of ASM but still need help.

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

I'm learning but sometimes I hit a brick wall, here is one of those walls.

 

This does not work as expected.

        "    dec    r18                    \n"  
        "    brne nextElement        \n"

 

this does.

        "    dec    r18                    \n" 
        "   cpi r18,0                \n"
        "    breq nextElement        \n" 

 

The expectation here is to branch when I hit 0 from a count down. I do load in 8 to my r18 but why do I have to use the compare? The brne should see the flag should it not? The later is either always branching, or never. I figured maybe its not my logic, maybe its my timing but this also does not work.

 

 

 

"    nop \n"        
"    dec    r18                    \n"  
"    brne nextElement        \n"

 

Both would count up to 3 instructions + jmp per loop?

 

 

I could be something else in my code and I'm determined to find it but I just need a sanity check here. Are my assumptions correct?

 

 

 

 

 

 

This topic has a solution.
Last Edited: Fri. Feb 19, 2021 - 08:18 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think the bug is not isolated to those lines.  Can you show more?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
ldi r17,0x10 ; Load constant in r17
loop: add r1,r2 ; Add r2 to r1
dec r17 ; Decrement r17
brne loop ; Branch if r17<>0
nop ; Continue (do nothing)

Here is a complete example from the AVR instruction set manual, how does the other code in your example differ

 

Jim

 

 

Keys to wealth:

Invest for cash flow, not capital gains!

Wealth is attracted, not chased! 

Income is proportional to how many you serve!

 

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


MattRW wrote:
I think the bug is not isolated to those lines.
+1

 

If this is about learning the avr-as syntax of AVR Asm I would start by doing it in .S files so you don't have the worries introduced when using inline Asm.

 

 

When I simulate that:

 

 

Status shows NZ after DEC and BRNE will loop back:

 

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

Ok, ill troubleshoot further. I thought I had it right..

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

 

Ok looks like it does count down but does not load back to 8.

asm volatile(
		"	clr %0					\n"//clear counter
		"	clr r17					\n"//clear temp
		"	ldi r18,8				\n"//set counter
		"	ld  r17, Z 				\n"//load Z to r17

		"	rjmp waitlow	\n"
"nextElement:\n"
SET_DBG
CLR_DBG
		"	ldi r18,8				\n"//set counter
		"	st  Z+, r17 			\n"//load r17 to z and go to next element in array
		"	ld  r17, Z 				\n"//load Z to r17
"waitlow:\n"
		" ldi r16, 0xff				\n"	

"waitlowl:\n"//start bit.
		"	inc r16					\n"//time out counter
		"	brmi exit			\n"// > 255, long enough for near 50us or so.
		"	sbic %2, 5				\n"//check if low,then skip
		"	rjmp waitlowl			\n"//wait while low.
		"	inc %0					\n"//count this bit.
		"	nop						\n"//move 1us in to place.
		"	nop						\n"
		"	nop						\n"
		"	nop						\n"
		"	nop						\n"
		"	nop						\n"
		"	nop						\n"
		"	nop						\n"
		"	nop						\n"
		"	nop						\n"
		"	nop						\n"
		"	nop						\n"

							// check at this time for bit state
		"	sbic %2, 5				\n"//if state was low skip
		"	sec   			  	    \n"//set Carry flag if true
		"	rol r17 				\n"//Rol flag on to r17

		"	ldi r16, 0xff				\n"
"waithigh:\n"
//find the next rising edge to sync
		"	inc r16					\n"
		"	brmi exit				\n" // > 255, long enough for near 50us or so.
		"	sbis %2, 5				\n" //check for set then skip
		"	rjmp waithigh			\n"	//go back not ready
		"	dec	r18					\n" //bit counter
		"	brne nextElement		\n"
		"	rjmp waitlow		\n" //next element in array

"exit:	\n"
		: 	"=&r" (count)						// %0
		: 	"z" ((unsigned char volatile *)nBuffer),		// %1
			"I" (_SFR_IO_ADDR(GCN64_DATA_PIN)),	// %2
			"I" (_SFR_IO_ADDR(PORTB))			// %3
		: 	"r16","r17","r18"
	);

I know my debug is not the best. The ICE is on the way.

 

 

The first 8 bits do count down but once it jumps to next element, its like the LDI didnt set r18 to 8? Please mind the code, I'm not finished, work my  way thru it.

 

 

Last Edited: Fri. Feb 19, 2021 - 06:37 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

Ah crap, never mind that. I miss interpreted my debug. The first part of the top is the send command, data start the first time the orange lines show up. So apparently its always branching to nextElement. Not that that makes any sense either but wanted to make that correction in my post.

 

Here is it using my

        "    dec    r18                    \n" //bit counter
        "    cpi r18,0                \n"
        "    breq nextElement        \n"

 

 

I really need to save the instruction.

Last Edited: Fri. Feb 19, 2021 - 07:40 PM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This does not work as expected.

        "    dec    r18                    \n"  
        "    brne nextElement        \n"

 

this does.

        "    dec    r18                    \n" 
        "   cpi r18,0                \n"
        "    breq nextElement        \n" 

 

Are you sure you have your branch senses correct?   Because in your initial post, the two examples will "take the branch" on OPPOSITE conditions.   The loop structure in your mote complete example seems a bit odd as well.

Don't you want something like:

  dec r18  ;; bit counter
  brne nextbit
  rjmp nextbyte

 

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

yes it works!

 

" "take the branch" on OPPOSITE conditions.  " - Right but the branch instruction is inverted also.

 

 

 

does brne check if a flag is set, or if r18 = 0? Maybe I had that backwards.

Last Edited: Fri. Feb 19, 2021 - 08:23 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

S_K_U_N_X wrote:

		"	inc r16					\n"//time out counter
		"	brmi exit			\n"// > 255, long enough for near 50us or so.

 

Actually brmi checks if the sign bit is set, or if the number is treated as unsigned, checks if it is >= 128. To do what the comment implies, you would need to check the carry flag. Since inc/dec don't touch the carry, you would need to add immediate 1 to r16 instead of using inc r16. But since the adi instruction doesn't exist, you would instead use subi:

 

		"	subi r16, -1			\n"//time out counter
		"	brcs exit			\n"// > 255, long enough for near 50us or so.

 

Last Edited: Fri. Feb 19, 2021 - 08:27 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

No, I know the brmi part is messed up, still developing that part. I'm talking about the code westfw  posted. For that code I plan to use the same count down from 255, just have not got to it yet.

Last Edited: Fri. Feb 19, 2021 - 08:29 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I believe that the reason that the construction:

     dec  r18

     brne someplace

 

doesn't work is due to the internal pipelining of the AVR.

The internal pipeline has two parts, the first part decodes the instruction, and the second part executes the instruction.

While the DEC is in the second part of the pipeline, the BRNE is in the first part.  The BRNE sees R18 before it is decremented.

 

If this is the case then:

   dec  r18

   nop

   brne someplace

 

should work OK.

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

the brmi will count 128 not 256

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

or

 

dec  r18

   brne someplaceElse, happens ever bit.

   brne someplace, only after 8

 

like posted above.

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

yeah BRMI, is not the question here. I only post all the code as it was asked for, that comment does not belong to that code.

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

I will try to make it more clear.

 

BRNE is BRanch Not Equal.

 

In ASM you think the way as a compare as a subtraction, if the result is 0 the numbers are Equal.

 

With your dec it's the same : Equal is if the result is zero.

Therefore #1 need to be breq

 

And forget #12 that is just noise no need for a nop.      

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

S_K_U_N_X wrote:
yeah BRMI, is not the question here.

 

Even though you want to focus on breq/brne, I noticed that error with brmi. I just mentioned it because it feels you need a better understanding of branch conditions in general. I don't think it's really OT.

Last Edited: Fri. Feb 19, 2021 - 09:45 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Debugging never replaces being careful---take a long & hard look at your code first.  Go through it thoroughly.  If you had a 5 million dollar prize on it working first time, bet it would! 

 

I believe that the reason that the construction:

     dec  r18

     brne someplace

doesn't work is due to the internal pipelining of the AVR.

 I don't think that is correct at all...otherwise it would be complete chaos on many fronts.  dec will always fully update the sreg before executing the next opcode. 

Now if you were talking about the old PICs& strange port read/writes, you might have a good book to sell.

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

Perfect explanation. sparrow2 , yes I understand now.

 

El Tangas , sure I get that but what I'm trying to say is this entire block of code is from an old project I didn't write it, those lines are not even redeveloped yet. I have never even heard of that particular op code and have no plan on using it for my design. Not that any of that would have been clear but figure I'd at-least explain they I'm not interested in it. Just focusing on one part at a time here.

Last Edited: Sat. Feb 20, 2021 - 03:09 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have a slight preference for “JZ/JNZ” sorts of mnemonics, which is less Ambiguous, clearly indicating either “the result was zero” or “the zero flag is true.”

but they didn’t ask me.

 

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

Glad to hear that still a few AVR freaks are programming in the wonderful AVR assembly language. 

 

To prevent the flag and label headache, years ago I wrote my precompiler s’AVR for structured AVR assembly language, which allows to write successful AVR assembly programs much quicker and easier to maintain.

 

Details see: www.led-treiber.de/html/s-avr.html

 

The Google or any other good translation tool might be helpful, if German is not your first language …

 

Using s’AVR since a few years, I even no longer need a debugger to make my AVR programs run as expected.

You will find quite a few complex s'AVR examples on my website.

 

English and German manuals are available for download.

 

BTW, here are some tips regarding the given loop troubles and how to prevent those: www.led-treiber.de/html/avr-tipps.html

 

Edit: Last link fixed (trailing letter was not included).

Last Edited: Sat. Feb 20, 2021 - 12:35 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Your last link don't seem to work!

 

My biggest problem with macros / preprocessors etc. is that you loss track of the flags, ( like will this loop change C!).

 

I rather have the real code is showed (even if you use a macro etc.). 

 

If you just want workable code use C

 

Perhaps it's just me that is a bit odd. 

Last Edited: Sat. Feb 20, 2021 - 12:27 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I rather have the real code is showed (even if you use a macro etc.). 

My favorite macro when doing asm is cut & paste  smiley  I find the old & use it for new.

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

sparrow2 wrote:
Your last link don't seem to work!
Fixed!

 

El Tangas wrote:

		"	subi r16, -1			\n"//time out counter
		"	brcs exit			\n"// > 255, long enough for near 50us or so.

That's another pitfall, as discussed in my tips (see link, which is OK now).

Here a REPEAT loop until the carry happens as an example (but also would work for EXITIF etc.):

 clr COUNT
 REPEAT
  .
  .
  .
  .
  subi COUNT,-1    ; SUBI -1 must be used instead of INC
 UNTIL NOT C       ; however, the carry is handled the opposite way!

Edit (code added), so above code should read:

		"	subi r16, -1			\n"//time out counter
		"	brcc exit			\n"// > 255, long enough for near 50us or so.

 

Last Edited: Sat. Feb 20, 2021 - 01:03 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

But as a general role you don't want to change C(arry) if you don't need to so 1 byte loops over 128 are best done with dec or inc and check for 0.

Or if you use pointers then a register could be loaded with the end value of the low byte of the pointer and then use CPSE (that is an oddball instruction because the instruction don't change any flags but is an other story)

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


 

Quite glad I initiated this thread, found all of this very helpful..

 

Ok so the code all works now, here is what I have. There seems to be one little issue left that I'm %99 sure is in my code.

 

After the code is complete I always have a bit that is on that should not be on.  Second byte, bit 5

After the first ST instruction something is setting my 5th bit. 

 

 

		asm volatile(
		"	clr %0					\n"//clear counter
		"	clr r17					\n"//clear temp
		"	ldi r18,8				\n"//set counter
		"	ld  r17, Z 				\n"//load Z to r17
		"	rjmp nextBit	\n"
"nextByte:\n"
		"	ldi r18,8				\n"//set counter back to 8
		"	st  Z+, r17 			\n"//load r17 to z and go to next element in array
		"	ld  r17, Z 				\n"//load Z to r17
"nextBit:\n"
		" 	ldi r16, 0xff			\n"
"waitlow:\n"//start bit.
		"	dec r16					\n" //time out counter
		"	breq exit				\n" //exit when we hi zero( carry flag and dec are equal. )
//find the next falling edge to sync
		"	sbic %2, 5				\n" //check if low,then skip
		"	rjmp waitlow			\n" //wait while low.
		"	nop						\n" //move 1us in to place.
		"	nop						\n"
		"	nop						\n"
		"	nop						\n"
		"	nop						\n"
		"	nop						\n"
		"	nop						\n"
		"	nop						\n"
		"	nop						\n"
		"	nop						\n"
		"	nop						\n"
	//	"	nop						\n"
		//"	nop						\n"
		//"	nop						\n"
		//"	nop						\n"
		CLR_DBG
		SET_DBG

// check at this time for bit state
		"	sbic %2, 5				\n" //if state was low skip
		"	sec   			  	    \n" //set Carry flag if true
		"	rol r17 				\n" //Rol flag on to r17
		"	inc %0					\n" //count bit.
		"	ldi r16, 0xff			\n"
"waithigh:\n"
//find the next rising edge to sync
		"	dec r16					\n"
		"	breq exit				\n" // exit when we hi zero( carry flag and dec are equal. )
		"	nop						\n"
		"	nop						\n"
		"	sbis %2, 5				\n" //check for set
		"	rjmp waithigh			\n"	//go back not ready
        "   dec    r18              \n" //bit counter
        "   brne nextBit      		\n" //If carry flag and dec are  not equal.
		"	rjmp nextByte			\n" //If carry flag and dec are equal. 

"exit:	\n"
		: 	"=&r" (count)						// %0
		: 	"z" ((unsigned char volatile *)nBuffer),		// %1
			"I" (_SFR_IO_ADDR(GCN64_DATA_PIN)),	// %2
			"I" (_SFR_IO_ADDR(PORTB))			// %3
		: 	"r16","r17","r18"
	);

 

 

Last Edited: Sat. Feb 20, 2021 - 04:45 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Unfortunately you did not submit any flowchart or (even better) a structogram (Nassi-Shneiderman diagram) of the given code snippet, so we would fully understand your intention. However, I guess the root cause might be missing clearing the carry before you shift anything unknown into r17:

		"	clc					\n" // clear carry before shifting
		"	sbic %2, 5				\n" //if state was low skip
		"	sec   			  	        \n" //set Carry flag if true
		"	rol r17 				\n" //Rol flag on to r17 

Writing structured s'AVR code you should have seen the missing part:

	IF %p2, 5
		sec
	ELSE
		clc
	ENDI
	rol	r17

I did not yet check the rest.

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

s'AVR wrote:

El Tangas wrote:

 

		"	subi r16, -1			\n"//time out counter
		"	brcs exit			\n"// > 255, long enough for near 50us or so.

 

 

That's another pitfall, as discussed in my tips (see link, which is OK now).

 

Yeah, my bad -1 = 0xFF. It will always set the carry except if r16 = 0xFF.

Last Edited: Sat. Feb 20, 2021 - 05:23 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I will also add this:

		"	dec r16					\n"
		"	breq exit				\n" // exit when we hi zero( carry flag and dec are equal. )

 Either bad comments or I don't get it.

dec don't change the carry flag and breq use Z not C(arry)

 

Add: of all your code only only these two lines change carry

		"	sec   			  	    \n" //set Carry flag if true
		"	rol r17 				\n" //Rol flag on to r17

 

Last Edited: Sat. Feb 20, 2021 - 05:44 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

westfw wrote:

I have a slight preference for “JZ/JNZ” sorts of mnemonics, which is less Ambiguous, clearly indicating either “the result was zero” or “the zero flag is true.”

but they didn’t ask me.

 

 

Yeah, it would've been nice if Atmel had kept the 8051 mnemonics.

 

I have no special talents.  I am only passionately curious. - Albert Einstein

 

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

 Either bad comments orI don't get it.

 bad comments, thx ;)

 

 

Thx s'AVR , all good now.

Last Edited: Sat. Feb 20, 2021 - 10:48 PM