How to track compilation process in Code Blocks or Atmel studio IDE?

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

i build my program and run it .. but i want to see or monitor how variables are saved and moving from blocks of memory to others ? 

how to do this? ,i use code blocks IDE ...is there any plugin to add or any software ? i want to see (behind the scene of compilation process).

 

i hope you understand what i mean guys

Last Edited: Mon. Jul 2, 2018 - 02:11 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This is not a general question - this is a specific question about a particular product.

 

CodeBlocks has nothing to do with Atmel or Microchip - their forums are here: http://forums.codeblocks.org/

 

http://www.codeblocks.org/

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

okay how to track compilation process in Atmel studio .. any thing to monitor compile process?

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

mustafa9 wrote:
i hope you understand what i mean

Not really.

 

It's unclear whether you really want to delve into the inner workings of the compiler, or if you actually just want to observe the operation of your code at runtime.

 

Note that CodeBlocks is not a compiler: http://wiki.codeblocks.org/index...

So, if you do want to delve into the inner workings of the compiler, you will need to go to the support site for whatever compiler it is that you're using.

 

Observing the operation of your code at runtime would come under "debugging" 

 

For details of how to use CodeBlocks, the user manual is here: http://www.codeblocks.org/user-manual

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Mon. Jul 2, 2018 - 02:15 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

mustafa9 wrote:
how to track compilation process in Atmel studio

It's reported in the 'Output' window

 

Take some time to review the Getting Started videos on the Atmel Studio page: http://www.microchip.com/mplab/avr-support/atmel-studio-7

 

EDIT

 

and Atmel Studio uses GCC, which is an Open Source compiler - so all the inner details are available for you to isnpect!

 

https://gcc.gnu.org/

 

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Mon. Jul 2, 2018 - 02:20 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Do you really mean compile/link time? The MAP and LSS files (Studio+gcc) will tell you a lot about what has been built but if you meant you want to monitor RAM at runtime you'll need an ICE and to run the debugger for that.

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

When you write:

 

but i want to see or monitor how variables are saved and moving from blocks of memory to others 

This sounds very much like run-time monitoring. If so, the debugger and the debug module inside every AVR will help you. HOWEVER, you need to be aware that the debug module CANNOT give you "live" information. When a break occurs, the module transfers program status information to the debugger. This is the ONLY time that you can view variable and register values and memory contents.  There is NO SOFTWARE that will get around this, because it is a property of the internal hardware of the microcontroller. 

 

It DOES seem "live" if you single-step because a single-step is just "break after this instruction".

 

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

Last Edited: Mon. Jul 2, 2018 - 07:24 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

When I reread this I guess you do mean the operation of the compiler? Good news is that it has myriad options to dump internal state as it operates. These are for the team who develop the compiler to make sure changes they apply are having the effect they hoped but be warned it can be very verbose and very complex and will probably mean little to anyone but the developers. Do you for instance know what gimple is? Or what an"insn"is? You could find it takes months/years before you understand all that and are in a position to understand internal compiler operation and be able to freely read its diagnostic output during the build.

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

clawson wrote:
You could find it takes months/years before you understand all that and are in a position to understand internal compiler operation

Indeed.

 

The inner workings of compilers is a specialist subject - well beyond the scope of this forum!

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:
inner workings of compilers is a specialist subject
Though GCC is pretty open about how it works...

 

https://gcc.gnu.org/onlinedocs/g...

 

It is a complex subject but that manual seems to be pretty well written and someone dedicated would be able to pick it up eventually. The key thing to understand about GCC is the concept of the frontend and backend being split. There is a generic language translator that converts (in our case) C or C++ to a standard form (the same whatever the machine architecture). Then there is a backend code generator that converts from this generic form to CPU specific code sequences. If GCC is ever found to be "sub-optimtal" it's almost certainly as a result of this circuitous route from source to Asm. A compiler written for the AVR alone has the potential to be more efficient in this respect.

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

clawson wrote:
A compiler written for [a specific architecture] alone has the potential to be more efficient in this respect.

Indeed.

 

This is where the likes of Keil, IAR, et al can actually win.

 

Also, GCC is a very general compiler - covers everything from embedded microcontrollers to big servers.

But the likes of Keil, IAR, et al are specifically focussed on the needs of embedded microcontrollers ...

 

Whether any gain is considered worth the cost is another matter ... 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Is this going to be another thread that mustafa9 just starts - and then ignores ... ?

 

frown

 

EDIT

 

See: https://www.avrfreaks.net/commen...

 

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Tue. Jul 3, 2018 - 10:39 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

A compiler written for [a specific architecture] alone has the potential to be more efficient in this respect.

awneil wrote:
Indeed.

 

This is where the likes of Keil, IAR, et al can actually win.

For an example, see: https://www.avrfreaks.net/commen...

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Tue. Jul 3, 2018 - 03:32 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks all for helping .

what i meant here is like debugging the code and see where variable like x is stored? in which register address in data memory? ..and where is the program counter flag is stopping now and what status registers contains and where is its address and so on like in the following example 

#include<stdio.h>

int main()

{

int x=5;

int y=4;

int sum=x+y; //i've put breakpoint here 

}

 i don't want to delve into the inner workings of the compiler,i want to observe the operation of my code at run time but i find it hard to do this and i don't understand how i observe it . i've tried debugging the code  

it asked me to choose debuger/programmer : i picked simulator ..then i click on debug and set my break point on the line of (int sum) i've added watchers also .

i don't know how to find it in assembly or may be i miss something that i should read or learn.

 

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

As you can see the compiler has simply discarded x, y, sum in your test code there. The compiler is an optimizing compiler. When it can see that no use is ever made of x, y or sum after the "sum = x + y" line it decides that the whole operation is completely pointless and does not bother to generate any code to create any of their variables or perform the addition. To understand more about this I suggest you read my tutorial:

 

https://www.avrfreaks.net/forum/...

 

There are various solutions:

 

1) to "switch off" optimization of individual variables you can make them "volatile". So if you used:

{
    int x = 5;
    int y = 3;
    volatile int sum = x + y;
}

then the optimiser would still see that there is no point in creating x or y and it knows at compile time that 5 + 3 is 8 so it would generate the single code sequence:

ldi R24, 8
sts sum, R24

It HAS to make a write to "sum" because the source code said it was "volatile" which means "it must be read or written when it appears in the code". But as I say this still discards x and y. If you REALLY wanted them to exist then you could use:

{
    volatile int x = 5;
    volatile int y = 3;
    volatile int sum = x + y;
}

In this case there has to be a write of 5 to a location called 'x' and there has to be a write of 3 to a location called 'y' but the compiler is still intelligent enough to know that the sum of 3 and 5 is 8 so it's unlikely it will actually perform an ADD so the generated code will likely be:

ldi R24, 5
sts x, R24
ldi R24, 3
sts y, R24
ldi R24, 8
sts sum, R24

2) a possibly better option is to put these variables OUTSIDE the body of a function so they are global. Also make them volatile. That way the compiler cannot make assumptions about their value as "something outside" may change them so:

volatile int x = 5;
volatile int y = 3;
volatile int sum;

{
   sum = x + y;
}

is more likely to generate the code you were hoping to see.

 

3) another option, though it is a dreadful idea, is to switch off optimisation all together by building with the option -O0 (rather that -O1, -O3, -Os, -Og or whatever is currently selected). With the optimiser off the compiler will generate code to make all the variables and do all the accesses your code appears to ask for. However it will do this for EVERYTHING in the entire program and make the most horribly bloated and inefficient code possible. This is all very well when you are trying little 3 line programs like this example but as soon as you write "real" code you will not want to continue doing this.

 

BTW when you write "real" AVR programs - things like running timers, accessing UART, reading PINs, writing LEDs on ports and so on then you won't need to worry about any of these things as all the inputs and outputs of these devices are "volatile" so will be read/written as required. This opens up another possibility and that is to discard "sum" from your code and write, instead, to some actual destination like PORTB or something. So:

volatile int x = 5;
volatile int y = 3;

{
   PORTB = x + y;
}

Often when I post example code sequences here on Freaks I do this very thing to ensure the code is not simply discarded by the optimiser.

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

The compiler decided your code did nothing useful and optimised it out of existence. Write some code that does something useful and try to debug it.

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

Even if the code does useful stuff, variables in registers cannot be followed (I think). Probably the best option is to set the variables you are interested in as volatile, as explained in #15, this way they will be stored in memory.

Using -O0 for the debug build works but it's a very blunt tool.

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

now it's clear .i've read about debugging but i missed the compiler optimization part.Thanks v much.

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

thanks all for helping

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

   i've made this 

{
    volatile int x = 5;
    volatile int y = 3;
    volatile int sum = x + y;
}

and this is what i gor for   

volatile int sum=x+y;

 

00000045  LDD R18,Y+1 Load indirect with displacement 

00000046  LDD R19,Y+2 Load indirect with displacement 

00000047  LDD R24,Y+3 Load indirect with displacement 

00000048  LDD R25,Y+4 Load indirect with displacement 

00000049  ADD R24,R18 Add without carry 

0000004A  ADC R25,R19 Add with carry 

0000004B  STD Y+6,R25 Store indirect with displacement 

0000004C  STD Y+5,R24 Store indirect with displacement 

}

 

not simple like  that ...how disassembly generated  like that ?

 

ldi R24, 5
sts x, R24
ldi R24, 3
sts y, R24
ldi R24, 8
sts sum, R24
Last Edited: Mon. Jul 9, 2018 - 12:48 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

That was, shall we say, pseudo-assembler just to illustrate the idea. But it's pretty obvious:

 

00000045  LDD R18,Y+1 Load indirect with displacement
00000046  LDD R19,Y+2 Load indirect with displacement
00000047  LDD R24,Y+3 Load indirect with displacement
00000048  LDD R25,Y+4 Load indirect with displacement
00000049  ADD R24,R18 Add without carry
0000004A  ADC R25,R19 Add with carry
0000004B  STD Y+6,R25 Store indirect with displacement
0000004C  STD Y+5,R24 Store indirect with displacement 

x is in Y+1:Y+2, y is in Y+3:Y+4 and sum is in Y+5:Y+6. They are int variables, so they take 16 bits on AVR (2 bytes).

 

AVR is RISC, it (mostly) doesn't have instructions that operate directly on memory variables, so the variables have to be loaded with LDD, the operation performed, then stored with STD.

Last Edited: Mon. Jul 9, 2018 - 01:18 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

But the code you got is what the compiler considers the "best" solution. (I found that when I tried it here). I was simply saying it might be "something like"  what I showed in my post above. Of course I was making the assumption that if you add 5 and 3 you would use 8 BIT variables but then your code uses 16 bit ("int" is 16 bit on AVR) so already that means that was read and write are going to be TWO 8 bit operations. Also you have chosen (against my advice) to keep the variables as locals not globals. That makes them what are called "stack frame automatics". To be re-entrant C creates any locals on the stack so what you have actually ommitted from this code is:

0000006c <main>:

int main(void) {
  6c:   cf 93           push    r28
  6e:   df 93           push    r29
  70:   00 d0           rcall   .+0             ; 0x72 <main+0x6>
  72:   00 d0           rcall   .+0             ; 0x74 <main+0x8>
  74:   00 d0           rcall   .+0             ; 0x76 <main+0xa>
  76:   cd b7           in      r28, 0x3d       ; 61
  78:   de b7           in      r29, 0x3e       ; 62
    volatile int x = 5;
  7a:   85 e0           ldi     r24, 0x05       ; 5
  7c:   90 e0           ldi     r25, 0x00       ; 0
  7e:   9e 83           std     Y+6, r25        ; 0x06
  80:   8d 83           std     Y+5, r24        ; 0x05
    volatile int y = 3;
  82:   83 e0           ldi     r24, 0x03       ; 3
  84:   90 e0           ldi     r25, 0x00       ; 0
  86:   9c 83           std     Y+4, r25        ; 0x04
  88:   8b 83           std     Y+3, r24        ; 0x03
    volatile int sum = x + y;
  8a:   2d 81           ldd     r18, Y+5        ; 0x05
  8c:   3e 81           ldd     r19, Y+6        ; 0x06
  8e:   8b 81           ldd     r24, Y+3        ; 0x03
  90:   9c 81           ldd     r25, Y+4        ; 0x04
  92:   82 0f           add     r24, r18
  94:   93 1f           adc     r25, r19
  96:   9a 83           std     Y+2, r25        ; 0x02
  98:   89 83           std     Y+1, r24        ; 0x01
  9a:   26 96           adiw    r28, 0x06       ; 6
  9c:   0f b6           in      r0, 0x3f        ; 63
  9e:   f8 94           cli
  a0:   de bf           out     0x3e, r29       ; 62
  a2:   0f be           out     0x3f, r0        ; 63
  a4:   cd bf           out     0x3d, r28       ; 61
  a6:   df 91           pop     r29
  a8:   cf 91           pop     r28
  aa:   08 95           ret

Now it is clearer what is going on. On entry to main(), because the "Y" register (that is R29:R28) are to be used the compiler saves them at the start and recovers them at the end:

  6c:   cf 93           push    r28
  6e:   df 93           push    r29
  a6:   df 91           pop     r29
  a8:   cf 91           pop     r28
  aa:   08 95           ret

In part it has done this because you have no endless loop in the program (usually a while(1) at the end) so there's a chance something might make a call to main() so it has to save/restore certain registers. The next bit is:

  70:   00 d0           rcall   .+0             ; 0x72 <main+0x6>
  72:   00 d0           rcall   .+0             ; 0x74 <main+0x8>
  74:   00 d0           rcall   .+0             ; 0x76 <main+0xa>
  76:   cd b7           in      r28, 0x3d       ; 61
  78:   de b7           in      r29, 0x3e       ; 62

at first this looks very "odd". There are 3 local CALLs to the very next instruction. But this is a very quick and clever way to reserve 2 bytes on the stack. Each of "x", "y" and "sum" are 2 bye (remember "int") variables so these 3 calls are creating room for x, y and sum on the stack. The compiler then does IN to read from SPL and SPH to read them into the two halves of "Y". So now the Y index register has the address of the 6 "empty" bytes on the stack. They can be accessed from Y+1 to Y+6. So next the compiler does:

    volatile int x = 5;
  7a:   85 e0           ldi     r24, 0x05       ; 5
  7c:   90 e0           ldi     r25, 0x00       ; 0
  7e:   9e 83           std     Y+6, r25        ; 0x06
  80:   8d 83           std     Y+5, r24        ; 0x05

That loads 0x0005 int two handy registers (GCC uses R24 and R25 as it's "work" registers most of the time). The 0x0005 value is then written to Y+6/Y+5 so those two bytes on the stack are where the compiler has chose to story 'x'. It does the same to set up 'y':

    volatile int y = 3;
  82:   83 e0           ldi     r24, 0x03       ; 3
  84:   90 e0           ldi     r25, 0x00       ; 0
  86:   9c 83           std     Y+4, r25        ; 0x04
  88:   8b 83           std     Y+3, r24        ; 0x03

This time storing 0x0003 to the two bytes at Y+3 and Y+4 which are where it has chosen to place 'y'. Finally we come to the sequence you quoted:

    volatile int sum = x + y;
  8a:   2d 81           ldd     r18, Y+5        ; 0x05
  8c:   3e 81           ldd     r19, Y+6        ; 0x06
  8e:   8b 81           ldd     r24, Y+3        ; 0x03
  90:   9c 81           ldd     r25, Y+4        ; 0x04
  92:   82 0f           add     r24, r18
  94:   93 1f           adc     r25, r19
  96:   9a 83           std     Y+2, r25        ; 0x02
  98:   89 83           std     Y+1, r24        ; 0x01

So that's doing exactly what you asked for. Remember that 'x' and 'y' are "volatile" which means it cannot just re-use the 0x0003 and 0x0005 it had loaded above. It MUST go back to the 'x' and 'y' locations and re-read them. So that's exactly what is happening here. It loads 'x' (Y+6/Y+5 you will remember) into R19:R18. It loads 'y' (Y+4/Y+3) into R25:R24. Then the ADD and ADC are what you were really trying to see. They are a 16 bit addition that adds R19:R18 onto the value in R25:R24 leaving the result in R25:R24. Finally this 16 bit value is stored into Y+2/Y+1 which is the location the compiler decided to place "sum" in. finally, because 6 bytes were created on the stack they have to be "undone" by:

  9a:   26 96           adiw    r28, 0x06       ; 6
  9c:   0f b6           in      r0, 0x3f        ; 63
  9e:   f8 94           cli
  a0:   de bf           out     0x3e, r29       ; 62
  a2:   0f be           out     0x3f, r0        ; 63
  a4:   cd bf           out     0x3d, r28       ; 61

That move SPH/SPL back up by 6 bytes with interrupt protection.

 

If you want to see an "efficient" version of all this then:

volatile unsigned char x = 5;
volatile unsigned char y = 3;
volatile unsigned char sum;

int main(void) {
    sum = x + y;
}

which generates:

00000092 <main>:
volatile unsigned char y = 3;
volatile unsigned char sum;


int main(void) {
    sum = x + y;
  92:   80 91 61 00     lds     r24, 0x0061     ; 0x800061 <x>
  96:   90 91 60 00     lds     r25, 0x0060     ; 0x800060 <__data_start>
  9a:   89 0f           add     r24, r25
  9c:   80 93 62 00     sts     0x0062, r24     ; 0x800062 <__data_end>

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
    volatile int x = 5;
  7a:   85 e0           ldi     r24, 0x05       ; 5
  7c:   90 e0           ldi     r25, 0x00       ; 0
  7e:   9e 83           std     Y+6, r25        ; 0x06
  80:   8d 83           std     Y+5, r24        ; 0x05

Interesting that the compiler doesn't use zero_reg here, loading r25 with zero instead.

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

It'd be the same length/cycles wouldn't it? Both MOV and LDI are 1 word and 1 cycle.

Last Edited: Mon. Jul 9, 2018 - 01:53 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

very nice explanation thanks much Mr. clawson & Eltangas.

i don't know if there is a tool or a kind of assembler that shows me for example : if i pointed with mouse to y+1/y+2 it shows that it's 2 byte of variable x or y+3/y+4 is y cause it uses 16 bit of AVR.. that would be more easier for beginners like me :) 

thanks you all

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

No, I mean:

 

    volatile int x = 5;
ldi     r24, 0x05       ; 5
std     Y+6, r1         ; 0x06
std     Y+5, r24        ; 0x05

Since r1 already is zero.

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

No, I mean:

Oh I see what you mean. yeah, you are right, that does look like a missed optimization. However I am using an "ancient" 4.9.2 so I don't necessarily have all the "goodies" that Georg-Johann has added in recent years so this would really need re-testing with an 8.x

mustafa9 wrote:
i don't know if there is a tool or a kind of assembler that shows me for example : if i pointed with mouse to y+1/y+2 it shows that it's 2 byte of variable x or y+3/y+4
Well the watch window in AS7 may well show this an annotation. So if you create a volatile 'x' and then add 'x' as a watch I think the watch window tells you that it is at Y+4 or whatever.

 

But really, to understand this stuff, just do exactly the same analysis as I did in #22. Learn to read the asm alongside the C. It helps to know that avr-gcc will always use Y as the "frame pointer" and everything on the stack frame will exists from Y+1 upwards. Of course working out that 'x' was actually assigned Y+5/Y+6 or whatever is something you can only really do by reading the code. If you wrote:

x = 12345;

then you see the generated code doing:

ldi r24, 0x39
ldi r25, 0x30
st Y+7, r24
st Y+8, r25

then you can be left in little doubt that the compiler assigned 'x' to Y+7/Y+8.

 

Another approach *may* be to -save-temps and -fverbose-asm. If I take my original version in #22:

int main(void) {
    volatile int x = 5;
    volatile int y = 3;
    volatile int sum = x + y;
}

then I build that with:

D:\atmel_avr\avr8-gnu-toolchain\bin>avr-gcc -mmcu=atmega16 -Os -fverbose-asm -save-temps avr.c -o avr.elf

D:\atmel_avr\avr8-gnu-toolchain\bin>

then study the .s file:

D:\atmel_avr\avr8-gnu-toolchain\bin>type avr.s
        .file   "avr.c"
__SP_H__ = 0x3e
__SP_L__ = 0x3d
__SREG__ = 0x3f
__tmp_reg__ = 0
__zero_reg__ = 1
 ;  GNU C (AVR_8_bit_GNU_Toolchain_3.5.4_1709) version 4.9.2 (avr)
 ;      compiled by GNU C version 4.7.4, GMP version 5.0.2, MPFR version 3.0.0, MPC version 0.9
 ;  GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
 ;  options passed:  -fpreprocessed avr.i -mn-flash=1 -mno-skip-bug
 ;  -mmcu=avr5 -Os -fverbose-asm
 ;  options enabled:  -Wmisspelled-isr -faggressive-loop-optimizations
 ;  -fauto-inc-dec -fbranch-count-reg -fcaller-saves
 ;  -fcombine-stack-adjustments -fcommon -fcompare-elim -fcprop-registers
 ;  -fcrossjumping -fcse-follow-jumps -fdefer-pop -fdevirtualize
 ;  -fdevirtualize-speculatively -fdwarf2-cfi-asm -fearly-inlining
 ;  -feliminate-unused-debug-types -fexpensive-optimizations
 ;  -fforward-propagate -ffunction-cse -fgcse -fgcse-lm -fgnu-runtime
 ;  -fgnu-unique -fguess-branch-probability -fhoist-adjacent-loads -fident
 ;  -fif-conversion -fif-conversion2 -findirect-inlining -finline
 ;  -finline-atomics -finline-functions -finline-functions-called-once
 ;  -finline-small-functions -fipa-cp -fipa-profile -fipa-pure-const
 ;  -fipa-reference -fipa-sra -fira-hoist-pressure -fira-share-save-slots
 ;  -fira-share-spill-slots -fisolate-erroneous-paths-dereference -fivopts
 ;  -fkeep-static-consts -fleading-underscore -fmath-errno
 ;  -fmerge-constants -fmerge-debug-strings -fmove-loop-invariants
 ;  -fomit-frame-pointer -foptimize-sibling-calls -fpartial-inlining
 ;  -fpeephole -fpeephole2 -fprefetch-loop-arrays -freg-struct-return
 ;  -freorder-blocks -freorder-functions -frerun-cse-after-loop
 ;  -fsched-critical-path-heuristic -fsched-dep-count-heuristic
 ;  -fsched-group-heuristic -fsched-interblock -fsched-last-insn-heuristic
 ;  -fsched-rank-heuristic -fsched-spec -fsched-spec-insn-heuristic
 ;  -fsched-stalled-insns-dep -fshow-column -fshrink-wrap -fsigned-zeros
 ;  -fsplit-ivs-in-unroller -fsplit-wide-types -fstrict-aliasing
 ;  -fstrict-overflow -fstrict-volatile-bitfields -fsync-libcalls
 ;  -fthread-jumps -ftoplevel-reorder -ftrapping-math -ftree-bit-ccp
 ;  -ftree-builtin-call-dce -ftree-ccp -ftree-ch -ftree-coalesce-vars
 ;  -ftree-copy-prop -ftree-copyrename -ftree-dce -ftree-dominator-opts
 ;  -ftree-dse -ftree-forwprop -ftree-fre -ftree-loop-if-convert
 ;  -ftree-loop-im -ftree-loop-ivcanon -ftree-loop-optimize
 ;  -ftree-parallelize-loops= -ftree-phiprop -ftree-pre -ftree-pta
 ;  -ftree-reassoc -ftree-scev-cprop -ftree-sink -ftree-slsr -ftree-sra
 ;  -ftree-switch-conversion -ftree-tail-merge -ftree-ter -ftree-vrp
 ;  -funit-at-a-time -fverbose-asm -fzero-initialized-in-bss

        .section        .text.startup,"ax",@progbits
.global main
        .type   main, @function
main:
        push r28         ;
        push r29         ;
         ; SP -= 6       ;
        rcall .
        rcall .
        rcall .
        in r28,__SP_L__  ;
        in r29,__SP_H__  ;
/* prologue: function */
/* frame size = 6 */
/* stack size = 8 */
.L__stack_usage = 8
        ldi r24,lo8(5)   ;  tmp46,
        ldi r25,0        ;
        std Y+6,r25      ;  x, tmp46
        std Y+5,r24      ;  x, tmp46
        ldi r24,lo8(3)   ;  tmp47,
        ldi r25,0        ;
        std Y+4,r25      ;  y, tmp47
        std Y+3,r24      ;  y, tmp47
        ldd r18,Y+5      ;  D.1461, x
        ldd r19,Y+6      ;  D.1461, x
        ldd r24,Y+3      ;  D.1461, y
        ldd r25,Y+4      ;  D.1461, y
        add r24,r18      ;  D.1461, D.1461
        adc r25,r19      ;  D.1461, D.1461
        std Y+2,r25      ;  sum, D.1461
        std Y+1,r24      ;  sum, D.1461
/* epilogue start */
        adiw r28,6       ; ,
        in __tmp_reg__,__SREG__
        cli
        out __SP_H__,r29         ; ,
        out __SREG__,__tmp_reg__
        out __SP_L__,r28         ; ,
        pop r29  ;
        pop r28  ;
        ret
        .size   main, .-main
        .ident  "GCC: (AVR_8_bit_GNU_Toolchain_3.5.4_1709) 4.9.2"

then some of the comments added by the code generator help. On a line like:

        std Y+6,r25      ;  x, tmp46
        std Y+5,r24      ;  x, tmp46

it's fairly obvious that 'x' has been assigned to Y+6 and Y+5 here. But we kind of knew that already from:

    volatile int x = 5;
  7a:   85 e0           ldi     r24, 0x05       ; 5
  7c:   90 e0           ldi     r25, 0x00       ; 0
  7e:   9e 83           std     Y+6, r25        ; 0x06
  80:   8d 83           std     Y+5, r24        ; 0x05

in my previous post - which just documents the action in a different way. At least with the .s file we know know that at the point 0x0005 is loaded the compiler has decided to call R25:R24 "tmp46" though I guess there's no real meaning to the 46 in this?

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

BTW a bit of self promotion but to make .s files easier to read I wrote this:

 

https://spaces.microchip.com/gf/...

 

so if I use it as follows:

D:\atmel_avr\avr8-gnu-toolchain\bin>avr-gcc -mmcu=atmega16 -Os -gdwarf-2 -fverbose-asm -save-temps avr.c -o avr.elf

D:\atmel_avr\avr8-gnu-toolchain\bin>avr-source avr.s
file 1 = avr.c

D:\atmel_avr\avr8-gnu-toolchain\bin>type avr.source.s
        .file   "avr.c"

  [SNIP!]

        .text
.Ltext0:

        .section        .text.startup,"ax",@progbits
.global main
        .type   main, @function
main:
//==> int main(void) {
        push r28         ;
        push r29         ;
         ; SP -= 6       ;
        rcall .
        rcall .
        rcall .
        in r28,__SP_L__  ;
        in r29,__SP_H__  ;
/* prologue: function */
/* frame size = 6 */
/* stack size = 8 */
.L__stack_usage = 8
//==>     volatile int x = 5;
        ldi r24,lo8(5)   ;  tmp46,
        ldi r25,0        ;
        std Y+6,r25      ;  x, tmp46
        std Y+5,r24      ;  x, tmp46
//==>     volatile int y = 3;
        ldi r24,lo8(3)   ;  tmp47,
        ldi r25,0        ;
        std Y+4,r25      ;  y, tmp47
        std Y+3,r24      ;  y, tmp47
//==>     volatile int sum = x + y;
        ldd r18,Y+5      ;  D.1461, x
        ldd r19,Y+6      ;  D.1461, x
        ldd r24,Y+3      ;  D.1461, y
        ldd r25,Y+4      ;  D.1461, y
        add r24,r18      ;  D.1461, D.1461
        adc r25,r19      ;  D.1461, D.1461
        std Y+2,r25      ;  sum, D.1461
        std Y+1,r24      ;  sum, D.1461
/* epilogue start */
//==> }
        adiw r28,6       ; ,
        in __tmp_reg__,__SREG__
        cli
        out __SP_H__,r29         ; ,
        out __SREG__,__tmp_reg__
        out __SP_L__,r28         ; ,
        pop r29  ;
        pop r28  ;
        ret
        .size   main, .-main
        .text
.Letext0:

This has combined the best of both worlds. You have "commented" source from the compiler but interleaved C source statements too.

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

thanks mr clawson for your efforts to answer my question ..

---------------------

I tried the same code on atmega 8 ..8 bit microcontroller and i found it as same as atmega 16 and 32

 

  volatile int sum=x+y;

 

0000002B  LDD R18,Y+1 Load indirect with displacement 

0000002C  LDD R19,Y+2 Load indirect with displacement 

0000002D  LDD R24,Y+3 Load indirect with displacement 

0000002E  LDD R25,Y+4 Load indirect with displacement 

0000002F  ADD R24,R18 Add without carry 

00000030  ADC R25,R19 Add with carry 

00000031  STD Y+6,R25 Store indirect with displacement 

00000032  STD Y+5,R24 Store indirect with displacement 

}

 

---------------------------------------------------------------------------

i thought  x and y and sum variables ..each one of them is is represented in only one byte but i see it is represented in 2 bytes in assembly ..i use 8 bit microcontroller (Atmega 8)

------

so what did i miss here ?how i see each variable is represented in one byte like (y+1 ) only for x.... not (y+1) and (y+2) for x  ?

Last Edited: Tue. Jul 10, 2018 - 02:42 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

On AVR C, interger is 2 byte size, to use only byte size declare your variable as int8_t (signed) or uint8_t (unsigned) like this:

 

    int A;     //2 byte signed integer
    int8_t B;  // 1 byte signed integer
    uint8_t C; // 1 byte unsigned integer
    
    

Jim

 

Click Link: Get Free Stock: Retire early!

share.robinhood.com/jamesc3274

 

 

 

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

And remember that if you want to use int8_t, uint8_t, uint32_t, etc., you need to add:

 

#include <stdint.h>
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

mustafa9 wrote:
I tried the same code on atmega 8 ..8 bit microcontroller and i found it as same as atmega 16 and 32
Why is that a surprise? They are all the same 8bit CPU core. The point I made (which you seem to have missed) is that in general you do not use "int" for AVR work. If you want "efficient" use for small integers you use "unsigned char" which is usually better accessed as "uint8_t" as long as <stdint.h> is being employed. That will reduce double load, doubles adds and double stores to single byte operations. Also as I said (twice now) above if you switch from local to global you won't see all the stack setup code and the Y+n frame refernecing. It will be simple LDS/STS as the storage locations are then fixed and known at link time (stack frame is dynamic and more complex). You could make "static" locals if you like - they too are pre-allocated in bss/data too. As I showed at the end of #22 above:

00000092 <main>:
volatile unsigned char y = 3;
volatile unsigned char sum;


int main(void) {
    sum = x + y;
  92:   80 91 61 00     lds     r24, 0x0061     ; 0x800061 <x>
  96:   90 91 60 00     lds     r25, 0x0060     ; 0x800060 <__data_start>
  9a:   89 0f           add     r24, r25
  9c:   80 93 62 00     sts     0x0062, r24     ; 0x800062 <__data_end>

That's with the variables as globals and "unsigned char" (aka uint8_t). As I just said an alternative might be:

#include <avr/io.h>

int main(void) {
    volatile static uint8_t x, y, sum;
    x = 3;
    y = 5;
    sum = x + y;
    while(1);
}

That is taking the variables off the stack and putting them into .bss. The code then becomes:

int main(void) {
    volatile static uint8_t x, y, sum;
    x = 3;
  7c:   83 e0           ldi     r24, 0x03       ; 3
  7e:   80 93 62 00     sts     0x0062, r24     ; 0x800062 <x.1484>
    y = 5;
  82:   85 e0           ldi     r24, 0x05       ; 5
  84:   80 93 61 00     sts     0x0061, r24     ; 0x800061 <y.1485>
    sum = x + y;
  88:   80 91 62 00     lds     r24, 0x0062     ; 0x800062 <x.1484>
  8c:   90 91 61 00     lds     r25, 0x0061     ; 0x800061 <y.1485>
  90:   89 0f           add     r24, r25
  92:   80 93 60 00     sts     0x0060, r24     ; 0x800060 <_edata>

 

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

"

And remember that if you want to use int8_t, uint8_t, uint32_t, etc., you need to add:

 

#include <stdint.h>

"

 

Are you sure? For PC/xxPis, I am sure ... as I had issues when using Arduino stuff -an advantage of standardized integers is that pieces of code can be checked every where-  (maybe it is already indirectly  included : anyway, including a well written include file  n (n>1)  times does not harm)...

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

dbrion0606 wrote:
And remember that if you want to use int8_t, uint8_t, uint32_t, etc., you need to add:
Well no actually. Because almost everything you do in C for AVR touches the registers you almost invariably have:

#include <avr/io.h>

in all code that you build and that already starts with an include of <stdint.h> so on the whole you can just start using the standard int types with no effort at all. In Arduino there is an implied include of <Arduino.h> and that in turn includes <avr/io.h> and that in turn includes <stdint.h> so, again, you can just start using stdint types without an explicit include of the header.

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

I was astonished by El Tangas answer (was right on PC/xxPi side ; one can live without **explicitely** -does not harm, any way-  invoking stdint.h , which should have puzzled me -I lazily bet it was indirectely included... and you gave the origin of what should have puzzled me ...)

 

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

Well, maybe it's just a result of my coding style, but I have quite a lot of source code that doesn't touch the I/O registers or needs anything from the avr/ include directory, for example functions that just do math, like CRC, moving averages, etc. so I have to include stdint.h explicitly quite often.

Last Edited: Wed. Jul 11, 2018 - 12:37 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

and it is useful to know that's the file you need.

 

Adding a superfluous #include won't hurt

 

EDIT

 

So perhaps you should just re-word it as:

And remember that if you want to use int8_t, uint8_t, uint32_t, etc., you need to have:

#include <stdint.h>

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Wed. Jul 11, 2018 - 02:36 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you guys so much for helping. it worked right with me and i understand it now

i was looking for (load indirect with displacement ) meaning and that leaded me to find that there are many types of (addressing modes) 

i found that my compiler uses mode (displacement mode ) in my case .

and i was asking why compiler uses that mode not something like (immediate mode or indirect mode or etc.. )? 

thank you

Last Edited: Thu. Jul 12, 2018 - 02:04 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The compiler will simply use what it considers the "best" access to data depending on the circumstance. It will tend to switch to indirect with offset when there are multiple accesses to some variable or register locations that are closely grouped. struct{}s often help it to recognise when things are grouped together (and so lend themselves to indirect+offset)

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

thank you v much