Uroš Platiše
17. April 1999
Even though small micro-controllers are getting stronger and stronger every day there is still a lot of code to be written in pure assembler. For example kernel itself, device drivers, fast interrupt routines, optimized mathematics functions, etc.
AVA (assembler and linker) was mainly designed for 8 and 16 bit micro-controllers but can be easily extended to 32 bit families also. In addition to standard assemblers for micro-controllers it features powerful segments and virtual symbols. These two features improve modular programming and allow objects to be completely independed from each other.
AVA integrates two packages:
AVA User's Manual is divided into the following chapters:
AVA is distributed as a source code and should compile on most of the UN*X systems. Hardware and software requirements for compilation and installation procedure are:
AVA can be downloaded from primary web site:
http://medo.fov.uni-mb.si/mappMirror sites are not available yet.
If you do not have former versions of AVA you have to download complete .tar.gz package and not just diff files. After you download the latest release extract it as:
tar -zxf ava-x.y.z.tar.gzEnter the ava-x.y.z directory and you shall see the following directory structure, where:
By the default AVA library is copied to the
/usr/local/lib/uTools/avadirectory and ava executable to the
/usr/local/bindirectory. If you disagree with the defaults, please edit the:
ava-x.y.z/src/Makefileand change directories to your requirements. This settings affects both, compilation and installation procedure.
Postscript and HTML version of the document is copied to the
/usr/doc/uTools/avaYou can change the default settings in the:
ava-x.y.z/doc/Makefile
Since AVA is a console application there are actually no parameters to be set by users individually. Simply enter the directory ava-x.y.z/src and type:
make
To install software change directory to ava-x.y.z/src and type:
make installAfter installation you may enter the ava-x.y.z/examples directory and type:
ava endian.sto compile and:
ava endian.oto link it. If this example did not work, compilation or installation procedure has failed. By the default the executable code is put into a.out file unless specified otherwise.
To install documentation in Postscript and HTML formats, change directory to ava-x.y.z/doc and type:
make install
AVA is a console application running in batch mode. It reads input either from a file or from the standard input (stdin). Output is written to another file or to the Standard Output (stdout). By default error messages are printed to the Standard Error (stderr).
Assembler and linker are integrated. Which of them is invoked is identified from the source filename extension. If Standard Input (stdin) and/or Standard Output (stdout) are specified AVA automatically invokes Assembler. Linker cannot use these two streams as input/output streams.
The following suffixes of source file names indicate kind of processing to be done:
General syntax of the AVA command line parameters:
ava -optionOne option can be specified after '-' character only. Full path name should be named for all files that are not found in the current directory.... -option
file
.x ... file
.x ... libraries
Several options are available to:
AVA options described in the following two sections are also documented on-line, using the -h switch. For example type:
ava -h
Options that take special effect on assembler source are further explained in the next chapter.
By default AVA produces uAsm output file format.
S0 header of the Motorola S-record format includes the name of the base segment coded in hex format. Example of the S-record header for the flash segment:
S0080000666c617368e9
Library is a directory of object files. It may also contain other files as long they do not have the suffix of the object file. The name of directory is simply the name of library.
It is important that libraries are maintaind in the right way. Each function should be placed in separate removable segments. Only in this case linker can check function dependencies and remove all unused pieces of code.
Example:
ava -v -v -o example example.o mylibwhere mylib is a directory in current directory.
Assembler source consists of elements called tokens. The token may be one of the following: numbers, string, quoted string, preprocessor directives, math and control symbols and remarks. To each type of token a range of valid characters is declared. If token does not match that range lexer produces an error and assembler terminates.
The types of tokens and ranges are represented in the table below.
Expressions are made of numbers, strings, math and control symbols. AVA expression solver understands the following operations:
((A operation B) {operation C})where A,B and C may be expressions also.
AVA provides C like preprocessor. Preprocessor directive starts with
character followed by a command. The table below lists the
supported directives:
Defines target device. This directive defines macro target_device and includes the file ../uTools/ava/arch.inc. File arch.inc declares memory model, actual device, memory mapped I/Os, ...etc. See content of the arch.inc for details.
/* set device */ #arch AT90S1200
Includes filename to the current source.
The file specified is first searched in the current
directory and if it is not found, AVA continues
searching in the alternative directories as specified
by the -Idirectory option on the command line
or by the adddir "filename"
directive in the source code.
/* define model */ #arch AT90S1200 /* Include standard bit definitions according to the selected device. */ #include "avr.inc"
/* target.inc */ /* Set additional include directories ... */ #adddir "../csys/include/asm" #adddir "../common/include/"
#ifdef __NICE_LEVEL # define __NICE_LEVEL 49 #endif
#if (__NICE_LEVEL < 41)| (__NICE_LEVEL > 58) # undefine __NICE_LEVEL # define __NICE_LEVEL 49 #endif
#ifdef __NICE_LEVEL # define __NICE_LEVEL 49 #else # undefine __NICE_LEVEL # define __NICE_LEVEL 49 #endif
/* Use of parethness is recommended because of the macro replacements. */ #ifndef __NICE_LEVEL # error "__NICE_LEVEL is not defined!" #endif
/* Prints __NICE_LEVEL to the stdout and log file */ #print "__NICE_LEVEL = " __NICE_LEVEL
The Architecture Definition File (arch.inc) is a part of the AVA library. This file includes all the information of the supported models and families.
The file arch.inc is automatically included after the
arch preprocessor directive.
AVA is a segment oriented assembler. Each piece of code may be placed in any kind of segment. Such a mechanism provides maximum control over the code and prevents from undesired errors (see section 4.4 for detailed explanation on segments).
One of the mechanism that helps to keep things in order is the Target Definition File or target.inc. For larger micro-controller systems with memory mapped I/Os, "huge" software, the target.inc file should provide complete hardware description. Using the -T option in the command the target.inc file will be included to each source automatically.
Of course, adding the line include "target.inc"
to each source has the same effect but -T option
might be used as a shortcut.
One of the most important things that the linker should be instructed is about memory holes. If linker is not notified about them, it cannot avoid these holes and data segment may be improperly placed! Please see examples in the chapter 5 and section 4.4 for help on declaring the memory holes.
There are two kind of symbols:
The present section describe general properties of the macros and labels. Attributes declare the different behaviours of the symbols during compilation and linkage process. The attributes are:
Symbol can have assigned multiple properties. But not all of them are valid. For example; symbol declared as (public, virtual) is invalid but (extern, virtual) is right. Note that attribute (extern) creates references outside the current object and (public) only exports the symbol. Virtual symbol can be only replaced by outside symbol if reference exist.
The following combinations make sense:
To label offset is assigned. General form of declaration:
attributes label_name{:}The semicolon ':' is required only if there is no attribute assigned to the label.
Macro replaces numbers with constants, expressions or even larger parts of code. General form of declaration:
If macro_string does not fit into one line, use thedefine attributes macro_name(
,
,...,
) macro_string
The general form can be written as:
define attributes macro_name(
,
,...,
) macro_string
![]()
![]()
macro_string![]()
![]()
...
macro_string![]()
![]()
macro_string![]()
On start-up AVA predefines some version information macros. AVA version 0.3.1 would declare them as shown in the following example:
The importance of the full control over the code is crucical and cannot be explained in one hour course. Specially if the target device has limited memory - okay, every machine on the planet is limited, but 1 or 8 kb of memory is something heavily under the normal range people know it from the PCs.
Treatment of segments is heavily extended in comparison to the other assemblers and linkers. The standard command
org offsetdoes not exist. Better result is achieved by using the higher order segments.
The AVA segments form multi-children tree structure just as like a file system. The root of the segments represents target its children define physical memory areas. Moreover this areas can be even expanded to abstract areas but let us describe them later on.
Simple representation of the program for the AVR micro-controller is shown in figure 4.1.
Here the flash, eeprom and eram are AVR base segments. They declare physical memory models and the downloading tool is expecting this segments.From some reasons it makes sense to define the segment order:
The segment orderNow we can say: base segments are segments of the first order.of the segment
is the number of vertices on the shortest path from the segment
to the root. The vertex of the segment
is also included.
The following segments attributes are available. Each attribute is described in greater details in further sections.
If we take a look at our previous example in figure 4.1 we see segment named eram. In any case, these segment has nothing to do in the output for the AVR micro-controller since downloading tool cannot load data to the volatile memory.
Every segment that is used for internal processing only is called abstract segment. This segment exist as such until the linker is finished.
The mechanism of abstract segment can be generalised and can be used for any kind of processing. For example: magic tables. The user can specify new segment to which every device driver defines a byte with a corresponding label. After linkage process to every byte an unique address is assigned and thus unique magic number in the corresponding label.
The removable attribute efficiently extends object files to libraries. Each function should be given be placed in its own higher order removable segment which consist at least ONE public label and not macro. If this public label was used at least once by other source the segment will be linked together with the rest of the code. Otherwise it is removed.
This attribute sets the final position of the segment and it must be specified to all first order segments. The segments which are not absolutelly positioned are called floating segments and are placed by AVA linker. The complete segmentation report is printed to the log file or to the standard output if log file is not given.
If the size of segment is not given the length may vary according to the usage. These segments are called variable segments. Because the root segment does not know the lengths of the first order segments their maximum size must be defined.
Let us go back to the example again where we have already said few words about the eram segment. Now imagine the second case
We declare some data within the eram segment and would like to get it there, anyhow, after the AVR wakes up.This typical example shows how does the C compiler work. The GNU C compiler stores data in the second order segment named gcc_data_section. Linker copies this data to the flash memory during the linkage process and checks for boundaries. The new segment in the flash memory is called mirror segment. The mirror segment must be declared before it is referenced.
Mirror segment copies all attributes from the original segment. These are:
Sets the alignment factor of the segment absolute address. The default segment alignment is set to 1 byte (no alignment).
Before we introduce the general form of the segment declaration line the general form of the segment name must be defined. Going back to our example we define:
segname =And the general form of the segment:.
.
...
seg attributes segname
The same form initializes or sets the segment. See examples in chapter 5.
/* Create and set the second order floating and variable segment to the eram segment named: data */ seg eram.data /* Map I/O memory ports to the eram segment of the AVR MCU. */ seg abs=0 size=0x20 eram.registers
The present section represents additional keywords for controlling the data storage and special keywords used by Architecture Definition File.
General declaration form:
ds.Reserves space in a segment with length![]()
![]()
/* reserve 32 bytes of space in eram.data segment */ seg eram.data buf: ds.b 0x20 /* and 20 words for table */ tbl: ds.w 20
General declaration form:
dc.Initializes constants in a segment of data type{number,string},{number,string},...
/* New Line Chatacter */ #define NL 10 /* Hello Message (split in several lines) */ seg flash.data hello: dc.b "Hello LED!",NL, "Hello again.",NL, 0 /* store address of the label for indirect call */ /* Note: PC counts words and not bytes (LSB must be removed) */ putc_f: dc.W _fputc >> 1
AVA understands the following data types:
and big endian as:![]()
where MSB is the most significant byte and LSB the less significant byte.![]()
General declaration form:
device AVA _Arch_Modul parameters ...This keyword is used by the Architecture Definition File only.
Please refer to the micro-controllers data book for complete list and explanation.
This chapter introduces simple examples and solutions some common problems. Examples are included in the examples directory.
The first typical example usually introduced by C and other languages is "Hello World!". Starting on a new micro-controller this "Hello World!" example is not that small piece of code. Driver for the UART/RS-232 module needs to be written, simple data structure as FIFO and printf function is required. All together counts about few hundreds bytes of code what is far too much for the first assembler program.
Let us better try to turn on and off a light emitting diode (LED) using the AT90S1200 AVR chip. Before going on please read chapter 4 which describes Assembler Language in details and section A.1 for AVR dedicated features.
There is one declaration that must be written in every source before first line of code appears. This is the target selection. Example:
#arch AT90S1200According to the AVR family (section A.1) we see that by default flash memory segment is selected. Thus every line after the
It is more safe to put each type of code into a separate segment of higher order which name reflects the purpose of that segment. Thus program could be put in the segment flash.code.
And that is all.
The following code turns on the led on port PB0 by setting the PB0 pin low.
/* examples/helloled.s */ /* set target device; see arch.inc for other models. */ #arch AT90S1200 /* Load include file of predefined port definitions. This file should not be included until device is selected. See inside of the avr.inc for details. */ #include "avr.inc" /* general declarations */ #define LED1 PB0 /* calculate port B direction */ #define PORTB_DIR BV(LED1) /* register naming */ #define Tmp r16 /* AVR AT90S1200 vectors start at address 0 */ seg abs=0 flash.code rjmp __reset_ /* this vector is executed on every reset */ reti reti reti /* Initialize hardware ports */ __reset_: ldi Tmp, PORTB_DIR /* set port B direction */ out DDRB, Tmp clr Tmp /* clear outputs and disable pull-ups */ out PORTB, Tmp loop: rjmp loop /* loop for ever */
Even though this example turn on the LED only it includes all the properties of a larger software written in assembler. When you write in assembler take special care on:
To the target.inc all hardware specifications should be given. The purpose of this file is to keep thousands lines of assembler code split in several files so far organised. Files that use target.inc can be compiled with -T option which automatically includes the target.inc. Otherwise the preprocessor line:
include "target.inc"present in each source of the project does completely the same. The -T switch forces the Target Declaration File to be read first. Follow the files given by the -I switch and then the assembler source.
An example is given in examples directory and prototype of the target.inc file is located in avalib directory (or in /usr/local/uTools/ava/target.inc).
The arch.inc file specifies the default parameters of the memory segments of the AVR family. If the target provides more memory the linker must be instructed. Otherwise it cannot be used.
Several macros are provided within the arch.inc. To change size of the RAM segment macro __ERAM_SIZE is provided as described in section A.1.
Even though AVA linker requires that only one object has set its segment size to the maximum value it is better to put that common properties in common file - the target.inc.
Example of target declaration:
/* Declare Size of the eram segment (before device declaration!) */ #define __ERAM_SIZE 0x1002 /* Declare MCU (AT90S8515 has enabled Wrap Around Option) */ #arch AT90S8515
The next very important thing are memory mapped ports. AVA linker cannot know where the target device has memory mapped ports if you do not declare them.
Memory mapped ports are declared as higher order segments of fixed size and fixed absolute address. Example:
/* Memory mapped IO ports of my test board */ #define _IO_PORTS 0x1000 /* Declare segments. Protect eram segment to clash with the following io registers. */ seg abs=_IO_PORTS size=0x2 eram.ioports /* Register Names: */ #define ADC_DATA _IO_PORTS #define ADC_CONTROL _IO_PORTS+1Besides segment declaration macros of the register names should also be provided.
The following specifications are provided as advanced information only and they are already considered in the arch.inc file.
AVA supports full range of AVR family micro-controllers. In general they can be all sorted in three groups.
device AVR group_numberin the source code.
Besides memory models AVR micro-controllers have different number of instructions. The following table represents the difference between first/second, second/third and third/fourth groups.
The following segments are provided within the arch.inc:
Segment sizes depend on a chosen model. Segments eram.registers and eram.io_space are of fixed size and have absolutely positioned segments.
The user should change the size of the RAM - eram segment. By the default, minimum values are used for all models - what includes internal SRAM only. Before declaring the device set __ERAM_SIZE as shown in the following example:
#define __ERAM_SIZE 0x8000 #arch AT90S8515As suggested by the AVA this kind of declarations should move to the target specific target.inc file.
By default, segment flash is selected.
The following flags are supported by the AVR family:
The AVA assembler performs check and reports warning if such a bug might happen. Since later revisions of the AVR MCUs have fixed that bug you might need to append the option
-favr_noskipbugto the command line in order to disable the AVA bug hunting mechanism.
This bug relates to the uisp as well which swaps the bytes of flash words. To use this option the latest version of the uisp package is required or other Motorola/Intel compatible downloading tool.
New releases, updates and other information can be found at AVA primary site:
http://medo.fov.uni-mb.si/mappYou can also subscribe to the MAPP AVR Mailing List
avr@fov.uni-mb.siTo subscribe, send message to:
majordomo@medo.fov.uni-mb.siwith the following text in the body of the message:
subscribe avr your_email_addressAdditional questions can be sent to my E-mail address:
uros.platise@ijs.si
Before reporting a bug please try to locate which part of the input code crashes down either assembler or linker. Send a detailed report to AVR Mailing List:
avr@fov.uni-mb.sior to my E-mail address:
uros.platise@ijs.si
Uros Platise Seljakovo naselje 45 SI-4000 Kranj Slovenia telephone: +386 64 312 457 E-mail: uros.platise@ijs.si
This document was generated using the LaTeX2HTML translator Version 99.2beta6 (1.42)
Copyright © 1993, 1994, 1995, 1996,
Nikos Drakos,
Computer Based Learning Unit, University of Leeds.
Copyright © 1997, 1998, 1999,
Ross Moore,
Mathematics Department, Macquarie University, Sydney.
The command line arguments were:
latex2html -show_section_numbers -auto_navigation -split 1 -html_version 3.0 -dir /tmp/avadoc ava.tex
The translation was initiated by Tjabo Kloppenburg on 2000-03-20