Analog Devices an572 Application Notes

AN-572
a
One Technology Way • P.O. Box 9106 • Norwood, MA 02062-9106 • 781/329-4700 • World Wide Web Site: http://www.analog.com
APPLICATION NOTE
Overlay Linking on the ADSP-219x
By David Starr
This applications note is for software designers starting an ADSP-219x overlay design. Using this note and the information in the Linker and Utilities Manual for ADSP­21xx Family DSPs the following may be done:
Divide a program into overlays. Write LDF files for simple and overlay links. Write an overlay manager.

HARVARD VS. PRINCETON ARCHITECTURE AND THE LINKER

Early in the history of computing, the modern design of one memory to hold both data and program instructions acquired the name “Princeton.” Such a machine is flex­ible because programs with lots of code and little data work, as well as programs with little code and lots of data. It’s simple in that address is the only memory parameter of interest. Performance is adequate, even though it takes two memory cycle times to fetch data from memory: one cycle to fetch the instruction and the second cycle for the instruction to fetch the data.
A faster architecture has separate program and data memories. This is “Harvard” architecture, which improves speed because the machine can fetch program instruc­tions and data in parallel; a data fetch from memory can thus be accomplished in a single memory cycle. All Analog Devices Inc. DSPs are Harvard architecture. They possess a separate program and data memory for speed and, for extra speed, data can be kept in program memory as well as data memory and there are instruc­tions to fetch data from both memories simultaneously. To use the full memory bandwidth, the ADSP-219x fam­ily possesses an instruction cache. Instructions come from cache, freeing up the program memory bus for data fetch from program memory. This permits multiply accumulate instructions to fetch a multiplier and a multi­plicand, compute a product, and add the new product to the accumulator, all in a single instruction. In this case, it is important to locate the multiplier data in pro­gram memory and the multiplicand data in data memory. It is the programmer’s responsibility to assign data buffers to memory. This is done with instructions to
the linker. Having a number of memories to deal with makes the DSP linker somewhat more complex than linkers for Princeton architecture machines.
In addition, each DSP project must fit into a different memory arrangement. Different DSP boards have differ­ent amounts of memory, located at different addresses. The ADSP-219x family supports an external memory interface, allowing rather large amounts of memory, but at a penalty in speed. Internal memory is ten times faster than external memory, so it may be desirable to keep large amounts of program code in external memory swap parts of it to internal memory for speed in execu­tion. Such a program is said to run in “overlays.”
For code reuse and portability, a program should not require modification to run in different machines or in different locations in memory. So the C or assembler source code does not specify the addresses of either code or data. Instead, the source code assigns names to
sections
time, leaving it up to the linker to assign physical memory addresses to each section of code or data. The goal is to make the source program’s position indepen­dent and let the linker assign all the addresses.
The address assignment task has become too much to handle with just command line switches to the linker. ADI has devised a “linker programming language” to allow full control of “what goes where.” Each DSP soft­ware project consists of one or more source code modules and a “linker description file” (.ldf file).
At link time, the linker follows directions in the .ldf file to place code and data at the proper addresses. The “linker programming language” is quite powerful and fairly complex. The manual for it is as thick as the classic “C Programming Language” by Kernighan and Ritchie. The .ldf file can select which compiler libraries are searched, which C run time start-up code is linked, and can supply all command line arguments and override all defaults. A default .ldf file is shipped with each release of the VDSP tools, and kept in the VDSP directories. VDSP allows an .ldf file as part of a project, as does a C source file. If a project does not contain an .ldf file, the linker will use
of code and/or data at compile or assembly
REV. 0
© Analog Devices, Inc., 2001
AN-572
the default one. If an .ldf file is included with the project, the project will link the same way each time, even if the default .ldf is edited or replaced by a new release of the VDSP tools, or the project is rebuilt on another computer with another version of the default .ldf file.

PHYSICAL MEMORY BLOCKS VS. LOGICAL MEMORY SECTIONS

What is the difference between a block and a section? A block is a named piece of the target system’s memory. Blocks have attributes of address, size, and width (16-bit vs. 24-bit). Sections are named pieces of code or data. .SECTION directives in the source file mark code/data as belonging to one named section or another. Typical .SECTION names are “program,” “dm_data,” and “pm_data.” Locate code and data at the desired address by putting code sections into memory blocks. The linker programming language uses “>” as the “put into” opera­tor, (not to be confused with C’s ‘greater than’ operator). The linker programming language has statements to define memory blocks, define code/data sections and marry the two together. When absolute addressing is needed (say to place an interrupt vector or to access memory-mapped I/O devices) define a memory block at the desired absolute address. Place the code or data into a .SECTION in the source file, and put the .SECTION into the memory block with the “put into” operator (“>”) in the .ldf file. The C compiler automatically places .SECTION directives into its output files. The compiler uses a series of default section names described in the compiler documentation.
This simple .ldf file defines one memory block (ram_blk) starting at 0 and ending at 64K. It defines one section named dontcare0 containing all the code in module frodo.doj, and puts the section into ram_blk, which starts at address 0. The section is named “dontcare0” to indicate that this name does NOT link to anything impor­tant. The name shows up in the link map but does not control which code goes where. This simple example has only one code module (frodo.doj). If the program had two modules, the INPUT_SECTIONS statement would look like:
dontcare0 {INPUT_SECTIONS (frodo.doj,bilbo.doj(program)} > ram_blk
A practical program would, of course, contain a signifi­cant number of modules, and listing them in the INPUT_SECTIONS statement would be tiresome. The linker programming language provides a macro facility using syntax like the UNIX make program. A macro $OBJ is defined as:
$OBJ = main.doj,frodo.doj,bilbo.doj,merry.doj,pippin.doj, sam.doj,… …. ….. gandalf.doj;
and the INPUT_SECTIONS statement might look like:
dontcare0 {INPUT_SECTIONS ($OBJ (program)}
> ram_blk
and, finally, to simplify matters, the linker has a convenient and automatically defined macro $COMMAND_LINE_OBJECTS, which is written:

THE LDF FILE

LDF files have two major parts (each delimited by curly brackets), the MEMORY part, and the PROCESSOR part. Statements inside the MEMORY part create memory blocks. The PROCESSOR part contains at least a SEC­TIONS command. The SECTIONS command uses more curly braces to enclose a number of statements. For example
MEMORY { ram_blk {TYPE (PM RAM) START (0x000000) END (0x00FFFF) WIDTH 24)} } PROCESSOR CORE1 {
SECTIONS {
dontcare0 {INPUT_SECTIONS
(frodo.doj (program))} > ram_blk
}
}
dontcare0 {INPUT_SECTIONS ($COMMAND_LINE_OBJECTS(program)} > ram_blk
In this way, modules can be added to the project without editing the .ldf file by hand each time a new module is added.
What does that (program) name do? It refers back to the source file. Assembly language module frodo.dsp looks like:
.section/CODE program
ax0 = dm(this_and_that); I0 = input_buffer; …. …. rts;
.section/DATA dm_data;
.var this_and_that; .var input_buffer[100];
….
–2–
REV. 0
AN-572
This (program) means take only the code in the source module .SECTION-named program. In this example, ram_blk will receive just the program code and NOT the .var- defined data buffers. The linker matches the name in () with the names in the .SECTION pseudo ops in the source code. In this way code from one source file can be split into different sections, which are put into differ­ent memory blocks.

A SIMPLE ASSEMBLER PROGRAM LINK

ARCHITECTURE(ADSP-219x) // Libraries from the command line are included in COMMAND_LINE_OBJECTS. $OBJECTS = $COMMAND_LINE_OBJECTS ; MEMORY { vector_blk { TYPE(PM RAM) START(0x000000) END(0x0000ff) WIDTH(24) } program_blk { TYPE(PM RAM) START(0x001000) END(0x06FFF) WIDTH(24) } dmdata_blk { TYPE(DM RAM) START(0x008000) END(0x009fff) WIDTH(16) } pmdata_blk { TYPE(PM RAM) START(0x07000) END(0x07FFF) WIDTH(16) }
}
PROCESSOR CORE1 { LINK_AGAINST( $COMMAND_LINE_LINK_AGAINST) OUTPUT( $COMMAND_LINE_OUTPUT_FILE )
One final note. The linker programming language syn­tax does NOT use ; as a statement terminator as does the assembler. Most linker programming language state­ments have a variable number of arguments enclosed in curly brackets. The closing curly bracket ends the state­ment. The syntax ignores white space (tab, space, CR, LF) in the same way that C does. The $MACROs, how­ever, require a terminating semicolon.
SECTIONS { dont_care_0 /* reset vector */ {
INPUT_SECTIONS( $OBJECTS(IVreset))
} > vector_blk dont_care_1 /* code space */ { INPUT_SECTIONS( $OBJECTS(program) ) } >program_blk
dont_care_2 /* data memory data */ { INPUT_SECTIONS( $OBJECTS(dm_data) ) INPUT_SECTIONS( $OBJECTS(dmdata) ) } >dmdata_blk
dont_care_3 /* Program memory DATA */ { INPUT_SECTIONS( $OBJECTS(pm_data) ) INPUT_SECTIONS( $OBJECTS(pmdata) ) } >pmdata_blk
} // end SECTIONS } // end PROCESSOR
REV. 0
–3–
Loading...
+ 5 hidden pages