Technical notes on using Analog Devices DSPs, processors and development tools
Contact our technical support at dsp.support@analog.com and at dsptools.support@analog.com
Or vi sit our o n-li ne r esou rces htt p:/ /www.analog.com/ee-notes and http://www.analog.com/processors
Configuring the C/C++ Run-Time Header for Blackfin® Processors
Contributed by Steve K Rev 1 – May 18, 2004
Introduction
The C/C++ run-time header (CRT) is the library
code that is executed when the processor jumps
to the
machine into a known state and calls
start address on reset. The CRT sets the
_main
1
. This
EE-Note describes the Blackfin® processor’s
CRT, and explains how to rebuild or reconfigure
it.
The document begins with an overview of the
CRT, which describes what the CRT does and
does not do. Each CRT activity is then examined,
followed by configuration instructions.
CRT Overview
global data declared by the application have been
initialized as required by the C/C++ standards.
It arranges things so that
_main appears to be
“just another function” invoked by the normal
function invocation procedure.
Not all applications require the same
configuration. For example, C++ constructors are
invoked only for applications that contain C++
code. The list of optional configuration items is
long enough that determining whether to invoke
each one in turn at runtime would be overly
costly. As a convenience, the Blackfin
processor’s CRT is supplied pre-built in several
different configurations, which can be specified
at link-time via LDF macros.
The CRT:
The CRT is used for projects that use C or C++.
Projects configured with VDK use a different
• Sets up required system services, such as
stack and event-handling
• Disables system services that power up in an
undefined state, such as circular buffers and
hardware loops
• Initializes standard library facilities, such as
standard input/output (
stdio)
• Invokes C++ constructors, as required
The CRT ensures that when execution enters
_main, the processor’s state obeys the C
Application Binary Interface (ABI), and that
1
In this document, all symbols are written with assembly
linkage, except where otherwise noted. Thus,
used, rather than
Copyright 2004, Analog Devices, Inc. All rights reserved. Analog Devices assumes no responsibility for customer product design or the use or application of
customers’ products or for any infringements of patents or rights of others which may result from Analog Devices assistance. All trademarks and logos are property
of their respective holders. Information furnished by Analog Devices applications and development tools engineers is believed to be accurate and reliable, however
no responsibility is assumed by Analog Devices regarding technical accuracy and topicality of the content provided in Analog Devices’ Engineer-to-Engineer Notes.
main().
_main is
run-time header, not described here (although the
principles are the same). Assembly language
projects do not provide a default run-time
header; you must provide your own.
The source for the Blackfin processor’s CRT is
located under the VisualDSP++® installation
directory, in the file
Blackfin\lib\src\libc\crt.
basiccrt.s, in the directory
The list of operations performed by the CRT can
include (not necessarily in the following order):
• Setting registers to known/required values
• Disabling hardware loops
• Disabling circular buffers
• Setting up default event handlers and
enabling interrupts
a
• Initializing the Stack and Frame Pointers
• Enabling the cycle counter
• Configuring the memory ports used by the
two DAGs
• Setting the processor clock speed
• Copying data from flash to RAM
• Initializing device drivers
• Setting up memory protection and caches
• Changing processor interrupt priority
• Initializing profiling support
• Invoking C++ constructors
• Invoking
• Invoking
_main, with supplied parameters
_exit on termination
What the CRT Does Not Do
The CRT does not set up physical memory
hardware. For example, external SDRAM is not
configured by the CRT in any way. This is left to
the boot loader because it is possible (and even
likely) that the CRT itself will need to be moved
into external memory before being executed.
The CRT in Detail
The CRT is provided as a single assembly source
file. It is assembled different ways to serve
different types of applications, running on
different processors. One source file is used to
generate CRTs for the following devices:
• ADSP-BF531 Blackfin processors
• ADSP-BF532 Blackfin processors
• ADSP-BF533 Blackfin processors
• ADSP-BF535 Blackfin processors
• ADSP-BF561 Blackfin processors
• AD6532 processors
platform-definition header and set up a few
constants:
IVBl and IVBh give the address of the Event
Vector Table.
UNASSIGNED_VAL is a bit pattern that indicates that
the register/memory location has not yet been
written to by the application. This value forms a
marker at the end of the call stack, and, if
UNASSIGNED_FILL is non-zero, will be written into
the Dregs and Pregs.
INTERRUPT_BITS is the default interrupt mask.
By default, it enables the lowest-priority
interrupt,
IVG15. This default mask can also be
overridden at runtime by your own version of
__install_default_handlers; see the Default
Event Handlers section for details.
For some platforms,
SYSCFG_VALUE is the
initialization value for the System Configuration
register (
SET_CLOCK_SPEED determines whether the CRT
SYSCFG).
will attempt to improve the processor’s default
clock speed. For ADSP-BF561 Blackfin
processors, ADSP-BF535 Blackfin processors,
and AD6532 processors, the clock speed is not
altered. For other processors, clock speed
depends on the silicon revision; a number of
accompanying definitions follow which may be
used to change the clock speed up to
approximately 600 MHz.
start and Register Settings
The CRT declares its first code label as start.
This required label is referenced by
.LDF files,
which explicitly resolve this label to the
processor’s reset address.
First, the CRT disables facilities that could be
enabled on start-up, due to their random powerup states, as follows:
•
Declarations
The CRT begins with a number of preprocessor
directives that “include” the appropriate
Configuring the C/C++ Run-Time Header for Blackfin® Processors (EE-238) Page 2 of 8
SYSCFG is set to SYSCFG_VALUE, according to
anomaly
#42 for ADSP-BF532 Blackfin
processors, anomaly #22 for ADSP-BF531
and ADSP-BF533 Blackfin processors, and
a
anomaly #12 for ADSP-BF561 Blackfin
processors.
• Hardware loops are disabled. This prevents
the jump-back-to-loop-start behavior should
the “loop bottom” register correspond to the
start of an instruction.
• Circular buffer lengths are set to zero. The
CRT makes use of the Iregs and calls
functions that may use them. Furthermore,
the C/C++ ABI requires that circular buffers
are disabled on entry to (and exit from)
compiled functions, so the circular buffers
must be disabled before invoking
Event Vector Table
_main.
The Event Vector Table is cleared. No event
handlers are defined except the reset vector
(fixed), emulation events (not touched by the C
ABI), and
event,
IVG15. The processor’s lowest-priority
IVG15, is set to point to supervisor_mode,
a label that appears later in the CRT.
The
___cplb_ctrl control variable is examined to
determine whether caching or memory protection
is required. If it is, an exception handler is
required to process possible events raised by the
memory system. Therefore, the default handler,
___cplb_hdr, is installed into the exception entry
of the Event Vector Table.
For details on
___cplb_ctrl, refer to “Caching
and Memory Protection” in the VisualDSP++
3.5 C/C++ Compiler and Library Manual for
Blackfin Processors [1].
Stack Pointer and Frame Pointer
The Stack Pointer (SP) is set to point to the top of
the stack, as defined in the
symbol
ldf_stack_end. Specifically, the Stack
.LDF file by the
Pointer is set to point just past the top of the
stack. Because stack pushes are pre-decrement
operations, the first push first moves the Stack
Pointer so that it refers to the actual stack top.
The User Stack Pointer (
(
FP) are set to point to the same address.
USP) and Frame Pointer
Twelve bytes are then claimed from the stack.
This is because the C ABI requires callers to
allocate stack space for the parameters of callees,
and that all functions require at least twelve bytes
of stack space for registers
R0-R2. Therefore, the
CRT claims these twelve bytes as the incoming
parameters for functions called before invoking
_main.
Default Event Handlers
The CRT sets up one or two event handlers (one
for changing processor mode; optionally, another
for handling memory system events), as reflected
by the event-enable bit mask. You may install
additional handlers; for your convenience, the
CRT calls a function to do this. The function,
__install_default_handlers, is an empty stub,
which you may replace with your own function
that installs additional or alternative handlers,
before the CRT enables events.
The function’s C prototype is:
short _install_default_handlers(short mask);
The CRT passes the default enable mask,
(
INTERRUPT_BITS) as a parameter, and considers
the return value to be an updated enable mask; if
you install additional handlers, you must return
an updated enable mask to reflect this.
Cycle Counter
The CRT enables the cycle counter, so that the
CYCLES and CYCLES2 registers are updated. This is
not necessary for general program operation, but
is desirable for measuring performance.
DAG Port Selection
For ADSP-BF531, ADSP-BF532, ADSP-BF533,
and ADSP-BF561 Blackfin processors, the CRT
configures the DAGs to use different ports for
accessing memory. This reduces stalls when the
DAGs issue memory accesses in parallel.
Configuring the C/C++ Run-Time Header for Blackfin® Processors (EE-238) Page 3 of 8
a
Clock Speed
If SET_CLOCK_SPEEDis set to one, the CRT
changes the default clock speed from
approximately 300 MHz to approximately
600 MHz, provided the silicon is of a suitable
revision. This is determined by reading the
DSPID
memory-mapped register and ensuring that the
silicon version is 0.2 or greater.
To change the clock speed, the CRT uses two
library routines with the following C prototypes:
int pll_set_system_vco(int msel, int df, int
lockcnt)
int pll_set_system_clocks(int csel, int
ssel)
These two routines return zero for success and
negative for error, but the CRT does not test their
return values.
EZ-KIT Lite™ boards use a 27 MHz on-board
clock. The CRT uses the following constants as
parameters to these routines to set the PLL and
clocks:
• VCO = 27*0x16 = 594 MHz
• CCLK = VCO = 594 MHz
The CRT does not enable external
!
memory. The configuration of physical
memory hardware is the responsibility
of the boot loader and must be
complete before the CRT is invoked.
Device Initialization (FIOCRT)
The CRT calls _init_devtab to initialize device
drivers that support
stdio. This routine:
• Initializes the internal file tables
• Invokes the
init routine for each device
driver registered at build-time
• Associates
stdin, stdout, and stderr with
the default device driver
Device initialization is an optional part of the
CRT; it is only performed when the CRT is
assembled with
FIOCRT defined.
For information on the device drivers supported
by
stdio, refer to “Extending I/O Support to
New Devices” in the VisualDSP++ 3.5 C/C++
Compiler and Library Manual for Blackfin
Processors [1].
• SCLK = VCO/5 = 118 MHz
Memory Initialization
Memory Initialization is a two-stage process:
1. At link-time, the Memory Initializer utility
processes the .DXE file to generate a table of
code and data memory areas that must be
initialized during booting.
2. At runtime, when the application starts, the
run-time library function
_mi_initialize
processes the table to copy the code and data
from the Flash device to volatile memory.
If the application has not been processed by the
Memory Initializer, or if the Memory Initializer
did not find any code or data that required such
movement, the
_mi_initialize function returns
immediately.
CPLB Initialization
If instruction or data Cache Protection Lookaside
Buffers (CPLBs) are to be enabled, the CRT calls
_cplb_init to do this, passing the value of
___cplb_ctrl as a parameter. For details on
CPLB initialization, refer to “Caching and
Memory Protection” in the VisualDSP++ 3.5
C/C++ Compiler and Library Manual for
Blackfin Processors [1].
Enable Interrupts
The interrupt-enable bit mask returned from
__install_default_handlers (but defaulting to
INTERRUPT_BITS) is used to enable interrupts. At
this point, the processor is still operating at Reset
priority, so pending events are still blocked from
occurring.
Configuring the C/C++ Run-Time Header for Blackfin® Processors (EE-238) Page 4 of 8
a
Lower Processor Priority
The CRT lowers the process priority to the
lowest supervisor mode level (
raises
IVG15 as an event, but this event cannot be
IVG15). It first
serviced while the processor remains at the
higher priority level of Reset. The CRT sets
to be the label
usermode, which is an empty
RETI
infinite loop, and then does a “return” from the
Reset interrupt (i.e., it executes an
RTI
instruction).
The processor mode changes to user mode and
recommences execution at the
the
usermode label, which also happens to be the
RETI address (i.e.,
following instruction). However, before this
infinite loop starts executing, the
IVG15 event,
which is pending, is taken; now that the
processor level has dropped, the
IVG15 event is
allowed to proceed.
The handler for
CRT and is the label
follows immediately after the infinite
IVG15 was set up earlier in the
supervisor_mode, which
usermode
loop. Thus, execution flows from the “return”
from Reset level to the
supervisor_mode label,
while changing processor mode from the highest
supervisor level to the lowest supervisor level.
If other events are enabled (memory
!
system exceptions or other events
installed via your own version of the
default handlers stub), they could be
taken between the return from Reset
and entering
IVG15. Therefore, the
remaining parts of the CRT may not
execute when event handlers are
triggered.
The CRT’s first action after entering
IVG15 is to
re-enable the interrupt system so that other
higher-priority interrupts can be processed.
Terminate Stack Frame Chain
Each stack frame is pointed to by the Frame
Pointer and contains the previous values of the
Frame Pointer and
instances of
RETS. The CRT pushes two
UNASSIGNED_VAL onto the stack,
indicating that there are no further active frames.
The C++ exception support library uses these
markers to determine whether it has walked back
through all active functions without finding one
with a
catch for the thrown exception.
Again, the CRT allocates twelve bytes for
outgoing parameters of functions that will be
called from the CRT.
Profiler Initialization (PROFCRT/PROFGUIDE)
If PROFCRT is defined, the instrumented-code
profiling library is initialized by calling
monstartup. This routine zeroes all counters and
ensures that no profiling frames are active.
Instrumented-code profiling is specified with the
–p, -p1, and –p2 compiler switches. If any of the
object files have been compiled to include this
profiling, the prelinker will detect this and will
set link-time macros to include a profiler-enabled
version of the CRT.
The instrumented-code profiling library
!
uses
accumulated profile data to
stdio routines to write the
stdout or
to a file. If PROFCRT is defined, FIOCRT
must also be defined. The default .
LDF
files include code for this.
If
PROFGUIDE is defined, the current version of the
CRT has a call to
code, and
PROFGUIDE should not be defined; it
___start_prof. This is legacy
will be removed in a later revision. (ProfileGuided Optimization is implemented within the
simulators, and not within the run-time libraries.)
Mark Registers (UNASSIGNED_FILL)
If UNASSIGNED_FILLis non-zero, the R2-R7 and P0-
P5 registers are set to UNASSIGNED_VAL.
Configuring the C/C++ Run-Time Header for Blackfin® Processors (EE-238) Page 5 of 8
C++ Constructor Invocation (CPLUSCRT)
If CPLUSCRT is defined,___ctorloop is invoked to
run all of the global-scope constructors.
a
Each global-scope constructor has a pointer to it
located in the
ctor section. When all of these
sections are gathered together during linking,
they form a table of function pointers. The
___ctorloop library function walks the length of
this table, invoking each constructor in turn. The
.LDF file arranges for the special object crtn.doj
to be linked after the CRT; it contains a
terminator for the
Argument Parsing (FIOCRT)
ctor table.
If FIOCRT is defined, __getargv is called to parse
any provided arguments (normally an empty list)
into the global array,
__Argv. This function
returns the number of arguments found which,
along with
parameters for
argc is set to zero and argv is set to an empty list,
__Argv, forms the argc and argv
_main. If FIOCRT is not defined,
statically defined within the CRT.
Calling _main and _exit
_main is called, using the argc and argv just
defined. Embedded programs are not expected to
return from
_main, but many legacy and non-
embedded programs do. Therefore, the return
value from
to gracefully terminate the application.
_main is immediately passed to _exit
_exit is
not expected to return.
•
PROFCRT: initializes instrumented-code
profiling (requires
FIOCRT)
•UNASSIGNED_FILL: fills registers with a
default “unused” pattern
•
SET_CLOCK_SPEED: raises clock speed to
600 MHz, if appropriate
•
_WORKAROUNDS_ENABLED: enables silicon-
revision anomalies
2
• Processor-specific operations
These options are set in different permutations to
produce the various CRTs supplied in preassembled form.
_WORKAROUNDS_ENABLED are indicated as having
FIOCRT, CPLUSCRT, PROFCRT, and
been set during assembly by filename suffices
“f”, “c”, “p”, and “y”, respectively. Thus,
crtsc532.doj has been assembled with CPLUSCRT,
for ADSP-BF532 Blackfin processors, and
crtsfp535.doj has been assembled with FIOCRT
and
PROFCRT for ADSP-BF535 Blackfin
processors. The “s” suffix indicates that the
processor invokes
is historical; the two CRTs
crtc532.doj are identical.
UNASSIGNED_FILL is not defined for any of the
_main in supervisor mode, and
crtsc532.doj and
pre-assembled CRT objects.
The run-time options are:
• Install exception handler for memory
Configuring the CRT
protection system exceptions
• Set the clock speed if the processor is of the
Available CRT Options
The preceding description notes where the CRT
conditionally executes some operations. These
appropriate silicon revision
• Install CPLBs and initialize the memory
protection system and any caching
can be divided into build-time and run-time
options.
Since
SET_CLOCK_SPEED is pre-defined to be zero
or one according to processor type (build-time)
The build-time options are:
•
FIOCRT: initializes device drivers and parses
command-line arguments
and the silicon revision is checked before
proceeding (run-time), changing the clock speed
falls mid-way between build-time and run-time
options.
•
CPLUSCRT: invokes global-scope C++
constructors
Configuring the C/C++ Run-Time Header for Blackfin® Processors (EE-238) Page 6 of 8
2
Not used in the CRT for the VisualDSP++ 3.5 release.
a
The default .LDF files select the CRT to be used,
according to various link-time macros. Defining
the macro at link-time directs the .
LDF file to
This LDF macro defined at link-time Selects CRT that had this macro defined at assembly-time