.org what does it do for USART Atmega 328p

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

Hello,

 

I am wondering about the .org in assembly, what it does and how it is represented in C. I have this assembly code that has

.org 0x00 ; Execute this when reset button is pushed

before the main execution starts and I am trying to understand what this means and what the C representation woudl be.

 

BTW the program is a USART that just a simple receiver/transmisson - reads UDR to char and then displays it.

Last Edited: Fri. Oct 16, 2020 - 02:21 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

LeonSteinn wrote:
I am wondering about the .org in assembly, what it does

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

 

LeonSteinn wrote:
and how it is represented in C.

It isn't:  the 'C' language doesn't control where stuff is located in memory - that's the job of the Linker.

 

Address zero is the Reset Vector - which is where the AVR starts fetching instructions after a reset or power-on.

 

In assembler, you have to specifically put the start of your code at that point;

In 'C', this is handled for you by the runtime support.

 

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

In assembler, .org tells the assembler "start placing code at this address in the memory space" it is short for Origin.

In a HLL such as c, that is left to the compiler and the decisions of the compiler maker, so there is not a direct equivalent, although the start of a function is similar, so

int main( void ) or int USART_read() would serve a similar function, "here is where the function starts". 

 

Note: the compiler maker may provide an extension for specifying a memory address, such as the location of a memory mapped register, etc. 

 

Jim

Edit: Andy is correct, it's the job of the linker to place code/data at memory addresses! 

 

(Possum Lodge oath) Quando omni flunkus, moritati.

"I thought growing old would take longer"

 

Last Edited: Fri. Oct 16, 2020 - 02:36 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0


The C compiler (well avr-gcc anyway) has something similar. It's called a "linker script". There are about 300+ AVRs and each falls into one of 18 families which have different kinds of memory layout. In AS7 for example you can find:

C:\Program Files (x86)\Atmel\Studio\7.0\toolchain\avr8>dir *.x /s
 Volume in drive C is OSDISK
 Volume Serial Number is 7AF3-B2D0

 Directory of C:\Program Files (x86)\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\avr\lib\ldscripts

25/06/2019  10:49             8,371 avr1.x
25/06/2019  10:49             8,376 avr2.x
25/06/2019  10:49             8,377 avr25.x
25/06/2019  10:49             8,378 avr3.x
25/06/2019  10:49             8,379 avr31.x
25/06/2019  10:49             8,378 avr35.x
25/06/2019  10:49             8,376 avr4.x
25/06/2019  10:49             8,378 avr5.x
25/06/2019  10:49             8,379 avr51.x
25/06/2019  10:49             8,379 avr6.x
25/06/2019  10:49             7,853 avrtiny.x
25/06/2019  10:49             8,381 avrxmega1.x
25/06/2019  10:49             8,381 avrxmega2.x
25/06/2019  10:49             8,469 avrxmega3.x
25/06/2019  10:49             8,381 avrxmega4.x
25/06/2019  10:49             8,381 avrxmega5.x
25/06/2019  10:49             8,381 avrxmega6.x
25/06/2019  10:49             8,381 avrxmega7.x

You mentioned Atmega328p. When you build C software for that and look at the .map file you will see:

 

 

In that complex path the "avr5" bit tells you that the 328P falls into architecture family "avr5" so the linker script used for it is:

 

 

it's a complex looking thing but it's basically a recipe that says "starting from location 0 I want you to lay out things in this order".

 

The key part of the file is where it defines the "text" section which basically means "all the program code that makes up this program". In part it looks like this:

  .text   :
  {
    *(.vectors)
    KEEP(*(.vectors))
    /* For data that needs to reside in the lower 64k of progmem.  */
     *(.progmem.gcc*)
    /* PR 13812: Placing the trampolines here gives a better chance
       that they will be in range of the code that uses them.  */
    . = ALIGN(2);
     __trampolines_start = . ;
    /* The jump trampolines for the 16-bit limited relocs will reside here.  */
    *(.trampolines)
     *(.trampolines*)
     __trampolines_end = . ;
    /* avr-libc expects these data to reside in lower 64K. */
     *libprintf_flt.a:*(.progmem.data)
     *libc.a:*(.progmem.data)
     *(.progmem*)
    . = ALIGN(2);
    /* For future tablejump instruction arrays for 3 byte pc devices.
       We don't relax jump/call instructions within these sections.  */
    *(.jumptables)
     *(.jumptables*)
    /* For code that needs to reside in the lower 128k progmem.  */
    *(.lowtext)
     *(.lowtext*)
     __ctors_start = . ;
     *(.ctors)
     __ctors_end = . ;
     __dtors_start = . ;
     *(.dtors)
     __dtors_end = . ;
    KEEP(SORT(*)(.ctors))
    KEEP(SORT(*)(.dtors))
    /* From this point on, we don't bother about wether the insns are
       below or above the 16 bits boundary.  */
    *(.init0)  /* Start here after reset.  */
    KEEP (*(.init0))
    *(.init1)
    KEEP (*(.init1))
    *(.init2)  /* Clear __zero_reg__, set up stack pointer.  */
    KEEP (*(.init2))
    *(.init3)
    KEEP (*(.init3))
    *(.init4)  /* Initialize data and BSS.  */
    KEEP (*(.init4))
    *(.init5)
    KEEP (*(.init5))
    *(.init6)  /* C++ constructors.  */
    KEEP (*(.init6))
    *(.init7)
    KEEP (*(.init7))
    *(.init8)
    KEEP (*(.init8))
    *(.init9)  /* Call main().  */
    KEEP (*(.init9))
    *(.text)
    . = ALIGN(2);
     *(.text.*)
    . = ALIGN(2);
    *(.fini9)  /* _exit() starts here.  */
    KEEP (*(.fini9))
    *(.fini8)
    KEEP (*(.fini8))
    *(.fini7)
    KEEP (*(.fini7))
    *(.fini6)  /* C++ destructors.  */
    KEEP (*(.fini6))
    *(.fini5)
    KEEP (*(.fini5))
    *(.fini4)
    KEEP (*(.fini4))
    *(.fini3)
    KEEP (*(.fini3))
    *(.fini2)
    KEEP (*(.fini2))
    *(.fini1)
    KEEP (*(.fini1))
    *(.fini0)  /* Infinite loop after program termination.  */
    KEEP (*(.fini0))
     _etext = . ;
  }  > text

So that will put anything in section called ".vectors" first then anything from .ini0 to .ini9 (in that order) after that, followed by all the stuff from .text (the bit you actually write) then everything from .fini0 to .fini9

 

Some of this stuff is described in the user manual here:

 

https://www.nongnu.org/avr-libc/...

 

When you build a C program the .map file (in part) shows you what was actually placed by the linker when it linked all the bits together..

.text           0x00000000       0xd4
 *(.vectors)
 .vectors       0x00000000       0x68 C:/Program Files (x86)/Atmel/Studio/7.0/Packs/Atmel/ATmega_DFP/1.4.351/gcc/dev/atmega328p/avr5/crtatmega328p.o
                0x00000000                __vector_default
                0x00000000                __vectors
 *(.vectors)
 *(.progmem.gcc*)
                0x00000068                . = ALIGN (0x2)
                0x00000068                __trampolines_start = .
 *(.trampolines)
 .trampolines   0x00000068        0x0 linker stubs
 *(.trampolines*)
                0x00000068                __trampolines_end = .
 *libprintf_flt.a:*(.progmem.data)
 *libc.a:*(.progmem.data)
 *(.progmem*)
                0x00000068                . = ALIGN (0x2)
 *(.jumptables)
 *(.jumptables*)
 *(.lowtext)
 *(.lowtext*)
                0x00000068                __ctors_start = .
 *(.ctors)
                0x00000068                __ctors_end = .
                0x00000068                __dtors_start = .
 *(.dtors)
                0x00000068                __dtors_end = .
 SORT(*)(.ctors)
 SORT(*)(.dtors)
 *(.init0)
 .init0         0x00000068        0x0 C:/Program Files (x86)/Atmel/Studio/7.0/Packs/Atmel/ATmega_DFP/1.4.351/gcc/dev/atmega328p/avr5/crtatmega328p.o
                0x00000068                __init
 *(.init0)
 *(.init1)
 *(.init1)
 *(.init2)
 .init2         0x00000068        0xc C:/Program Files (x86)/Atmel/Studio/7.0/Packs/Atmel/ATmega_DFP/1.4.351/gcc/dev/atmega328p/avr5/crtatmega328p.o
 *(.init2)
 *(.init3)
 *(.init3)
 *(.init4)
 *(.init4)
 *(.init5)
 *(.init5)
 *(.init6)
 *(.init6)
 *(.init7)
 *(.init7)
 *(.init8)
 *(.init8)
 *(.init9)
 .init9         0x00000074        0x4 C:/Program Files (x86)/Atmel/Studio/7.0/Packs/Atmel/ATmega_DFP/1.4.351/gcc/dev/atmega328p/avr5/crtatmega328p.o
 *(.init9)
 *(.text)
 .text          0x00000078        0x2 C:/Program Files (x86)/Atmel/Studio/7.0/Packs/Atmel/ATmega_DFP/1.4.351/gcc/dev/atmega328p/avr5/crtatmega328p.o
                0x00000078                __vector_22
                0x00000078                __vector_1
                0x00000078                __vector_24
                0x00000078                __vector_12
                0x00000078                __bad_interrupt
                0x00000078                __vector_6
                0x00000078                __vector_3
                0x00000078                __vector_23
                0x00000078                __vector_25
                0x00000078                __vector_13
                0x00000078                __vector_17
                0x00000078                __vector_19
                0x00000078                __vector_7
                0x00000078                __vector_5
                0x00000078                __vector_4
                0x00000078                __vector_9
                0x00000078                __vector_2
                0x00000078                __vector_21
                0x00000078                __vector_15
                0x00000078                __vector_8
                0x00000078                __vector_14
                0x00000078                __vector_10
                0x00000078                __vector_16
                0x00000078                __vector_18
                0x00000078                __vector_20
 .text          0x0000007a       0x56 main.o
                0x0000007a                timer1_init
                0x000000a4                __vector_11
                0x000000c8                main
 .text          0x000000d0        0x0 c:/program files (x86)/atmel/studio/7.0/toolchain/avr8/avr8-gnu-toolchain/bin/../lib/gcc/avr/5.4.0/avr5\libgcc.a(_exit.o)
                0x000000d0                . = ALIGN (0x2)
 *(.text.*)
 .text.libgcc.mul
                0x000000d0        0x0 c:/program files (x86)/atmel/studio/7.0/toolchain/avr8/avr8-gnu-toolchain/bin/../lib/gcc/avr/5.4.0/avr5\libgcc.a(_exit.o)
 .text.libgcc.div
                0x000000d0        0x0 c:/program files (x86)/atmel/studio/7.0/toolchain/avr8/avr8-gnu-toolchain/bin/../lib/gcc/avr/5.4.0/avr5\libgcc.a(_exit.o)
 .text.libgcc   0x000000d0        0x0 c:/program files (x86)/atmel/studio/7.0/toolchain/avr8/avr8-gnu-toolchain/bin/../lib/gcc/avr/5.4.0/avr5\libgcc.a(_exit.o)
 .text.libgcc.prologue
                0x000000d0        0x0 c:/program files (x86)/atmel/studio/7.0/toolchain/avr8/avr8-gnu-toolchain/bin/../lib/gcc/avr/5.4.0/avr5\libgcc.a(_exit.o)
 .text.libgcc.builtins
                0x000000d0        0x0 c:/program files (x86)/atmel/studio/7.0/toolchain/avr8/avr8-gnu-toolchain/bin/../lib/gcc/avr/5.4.0/avr5\libgcc.a(_exit.o)
 .text.libgcc.fmul
                0x000000d0        0x0 c:/program files (x86)/atmel/studio/7.0/toolchain/avr8/avr8-gnu-toolchain/bin/../lib/gcc/avr/5.4.0/avr5\libgcc.a(_exit.o)
 .text.libgcc.fixed
                0x000000d0        0x0 c:/program files (x86)/atmel/studio/7.0/toolchain/avr8/avr8-gnu-toolchain/bin/../lib/gcc/avr/5.4.0/avr5\libgcc.a(_exit.o)
                0x000000d0                . = ALIGN (0x2)
 *(.fini9)
 .fini9         0x000000d0        0x0 c:/program files (x86)/atmel/studio/7.0/toolchain/avr8/avr8-gnu-toolchain/bin/../lib/gcc/avr/5.4.0/avr5\libgcc.a(_exit.o)
                0x000000d0                _exit
                0x000000d0                exit
 *(.fini9)
 *(.fini8)
 *(.fini8)
 *(.fini7)
 *(.fini7)
 *(.fini6)
 *(.fini6)
 *(.fini5)
 *(.fini5)
 *(.fini4)
 *(.fini4)
 *(.fini3)
 *(.fini3)
 *(.fini2)
 *(.fini2)
 *(.fini1)
 *(.fini1)
 *(.fini0)
 .fini0         0x000000d0        0x4 c:/program files (x86)/atmel/studio/7.0/toolchain/avr8/avr8-gnu-toolchain/bin/../lib/gcc/avr/5.4.0/avr5\libgcc.a(_exit.o)
 *(.fini0)
                0x000000d4                _etext = .

As others have said, the great thing about C is that you never need to worry about any of this stuff (unless you are doing complex stuff like writing bootloaders or something like that). You just write:

#define F_CPU 8000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

void timer1_init()
{
	TCCR1B |= (1 << WGM12)|(1 << CS12);    //sets up timer with prescaler 256 and CTC mode
	TCNT1 = 0;                            //initialize counter
	OCR1A = 15623;                        //initialize compare value
	TIMSK1 |= (1 << OCIE1A);            //enable compare interrupt
}

ISR(TIMER1_COMPA_vect)                    //Interrupt service routine
{
	PORTC ^= (1 << 0);                    //Toggle led
}

int main(void)
{
	sei();
	DDRC |= (1 << 0);
	
	timer1_init();                        //Initialize timer 1
	
	while(1)
	{
		
	}
	
}

and the linker puts all this stuff in all the right places.

 

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

clawson wrote:
The key part of the file is where it defines the "text" section which basically means "all the program code that makes up this program". In part it looks like this:
To be precise, it is a convention so ubiquitous that it is often mistaken for a law of nature.

The linker and the compiler need to use the same convention.

The assembler is convention-agnostic.

Iluvatar is the better part of Valar.

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

In 'C', this is handled for you by the runtime support.

Which means that for MOST applications, the C compiler will put "standard startup code" at ".org 0" that eventually calls the main() function.

So as long as a C program defines main(), it doesn't need to do anything else WRT defining memory locations for code.

OCCASIONALLY, you may want to replace the standard startup code (because it's too big for a really space-constrained application, for example), and in that case you need to look at linker scripts or named sections or something.  And maybe prevent the linker from including the standard startup code.  But this is NOT usually needed.