world leader in high performance signal processing
Trace: » port_assembly_code

Porting Visual DSP++ assembly source code to the GNU Toolchain

Before taking the effort to port an assembly routine from VDSP to the GNU Toolchain, you need to understand what executable file format you will be using:

  • FLAT : Binary Flat files commonly known as BFLT, are a relatively simple and lightweight executable format based on the original a.out format.
  • ELF : The executable and linking format (ELF) was originally developed by Unix System Laboratories and has become the standard in file formats. The ELF standard has greater power and more flexibility than the FLAT format. However, they are more heavyweight, requiring more disk space and having a small run-time penalty.

The 2 executable file formats, have 2 different C ↔ assembly calling interfaces. For more details, please look at the description of the application_binary_interface (ABI).

Here are some common guide lines when porting VDSP++ source to Linux:

File Names

Visual DSP++ (VDSP) assembly code normally has a .asm file suffix, while the GNU assembler (gas) requires assembly files to have either .S or .s file suffix. Other file suffixes which control the output type of the gnu toolchain are documented in the gcc manual.

Both .asm and .S file types can contains preprocessing commands, assembler directives, comments etc, which needs to be pre-processed. (GNU files which have the .s are not passed through the C pre-processor) Since gas or gcc does not recognize the *.asm files by default, you must tell it explicitly the files are assembler. This is done with the -x assembler or -x assembler-with-cpp flags. Using the following command line syntax, VDSP *.asm files can be consumed by the gnu toolchain:

bfin-uclinux-gcc -x assembler-with-cpp test.asm -o test.o
  • -x assembler-with-cpp : option tells GCC the input file is an assembly file which must be passed through the C preprocessor, and is the GNU equivalent of a .S file.
  • -x assembler : option tell GCC the file is assembler code, and is the GNU equivalent of a .s file.

Keeping Source Common

Although there are many differences between the GNU Toolchain and VDSP is is possible to keep all source files common, so it does not matter which toolchain is used. Both toolchains include Predefined Macros which can be used to tell the compilers apart at compile time. GNUC and VDSP can be used in source files to control the differences between the different compilers. For example:

.if defined (__GNUC__)
array_1:
.short 0, 1, 2;
.else
.byte2 array_1[3] = 0, 1, 2;
.endif

Will compile properly on both toolchains. The differences in the assembler directives will be reviewed in detail in the next section.

Assembler Built-Ins

Visual DSP provides some assembly builtins like OFFSETOFF() and SIZEOF() which allow you to provide C level structure names. The GNU assembler however does not provide any functionality like this. Please see the C structs and GAS document for some possible workarounds.

Assembler Directives

Directives in an assembly source file control the assembly process. Unlike assembly instructions, directives do not produce opcodes during assembly. Use the following general syntax for assembler directives:

.directive [/qualifiers |arguments];

Each assembler directive starts with a period (.) and ends with a semicolon (;). Some directives take qualifiers and arguments. A directive’s qualifier immediately follows the directive and is separated by a slash (/); arguments follow qualifiers. Assembler directives can be uppercase or lowercase.

Many VDSP Assembler Directives are not recognized by GCC, and GCC directives are not recognized by VDSP. We need control which directives each toolchain sees. A list of gas assembler directives can be found in the gas manual.

VDSP GNU Description
.ALIGN .align Specifies an alignment requirement for data or code
.BYTE .BYTE2 .BYTE4 .byte .short .word .int .space Defines and initializes one-, two-, and four-byte data objects, respectively.
.ELSE .else .elseif Conditional assembly directive
.ENDIF .endif Conditional assembly directive
.EXTERN .extern Allows reference to a global symbol. Since gas treats all undefined symbols as external, this is accepted and ignored
.EXTERN STRUCT .extern Allows reference to a global symbol (struct) that was defined in another file. Since gas treats all undefined symbols as external, this is accepted and ignored
.FILE .file Overrides filename given on the command line.
.GLOBAL .global Changes a symbol’s scope from local to global
.IF .if Conditional assembly directive
.IMPORT Provides the assembler with the structure layout (C struct) information
.INC/BINARY .include .incbin Includes the content of file at the current location.
.LEFTMARGIN
.LIST .list Starts listing of source lines
.LIST_DATA Starts listing of data opcodes
.LIST_DATFILE Starts listing of data initialization files
.LIST_DEFTAB Sets the default tab width for listings
.LIST_LOCTAB Sets the local tab width for listings
.LIST_WRAPDATA Starts wrapping opcodes that don’t fit listing column
.NEWPAGE Inserts a page break in a listing
.NOLIST .nolist Stops listing of source lines
.NOLIST_DATA Stops listing of data opcodes
.NOLIST_DATFILE Stops listing of data initialization files
.NOLIST_WRAPDATA Stops wrapping opcodes that don't fit listing column
.PAGELENGTH .psize Defines the length of a listing page
.PAGEWIDTH .psize Defines the width of a listing page
.PREVIOUS .previous .popsection Reverts to a previously described .SECTION
.SECTION .section .pushsection Marks the beginning of a section
.STRUCT Defines and initializes data objects based on C typedefs from .IMPORT C header files
.TYPE .type Changes the default data type of a symbol; used by C compiler
.VAR .int Defines and initializes 32-bit data objects
.WEAK .weak or .weakref Creates a weak definition or reference

The VDSP++ examples were taken from Visual DSP++ 4.0 Assembler and Preprocessor Manual, Revision 1.0, January 2005 Part Number: 82-000420-04. Further Updates in VDSP++ may change these directives. Since we are not VDSP++ developers, please let us know if you see a problem.

Examples

  • .byte2 to .short for initialized data
    .if defined (__GNUC__)
    array_1:
    .short 0, 1, 2;
    .else
    .byte2 array_1[3] = 0, 1, 2;
    .endif
  • .byte4 to .long for initialized data
    .if defined (__GNUC__)
    array_1:
    .long 0, 1, 2
    .else
    .byte4 array_1[3] = 0, 1, 2;
    .endif
  • Define uninitialized data using .space
    .if defined (__GNUC__)
    .align 4;
    array_1:
    .space 12;
    .else
    .byte4 array_1[3];
    .endif

Here “array_1” is forced to be 4-byte aligned, since VDSP assembler aligns data defined as ”.byte4” to 4 bytes boundary.

Sometimes the ASM code is written with the assumption of data alignment and memory layout (that is, the order of data allocation in memory). Although this assumption is not good coding style, special care is needed to make sure that the translation do not change alignment and ordering of data in memory.

For more information on Gnu assembler directives, refer to the manual here: http://sourceware.org/binutils/docs/as/.