Using GNU Toolchain to Debug Applications on EM Starter Kit
To learn how to build and debug application using Eclipse IDE, please use ARC GNU IDE manual.
You can find all necessary information about configuring the board and connecting to UART in a User Guide which is published in ARC EM Starter Kit section on ARC Development Systems Forum.
Prerequisites
A toolchain for Linux and Windows hosts can be downloaded from the GNU Toolchain
Releases page.
OpenOCD for debugging applications on hardware boards is shipped with IDE bundle only.
OpenOCD binary (openocd
for Linux and openocd.exe
for Windows) resides in bin
directory of IDE.
Download and install Digilent Adept runtime and utilities to be able to work with EM Starter Kit on Linux. In order to use OpenOCD on Windows it is required to install appropriate WinUSB drivers, see How to Use OpenOCD on Windows for details.
Building a Simple Application
Consider this simple application (assume that it’s saved in main.c
):
int main()
{
return 0;
}
Different core templates in EM Starter Kit use different memory maps.
It means that you need to use a special memory map file with .x
extension
to be able to compile and run your application on EM Starter Kit.
In first, clone toolchain
repository and look into extras/dev_systems
directory. This directory contains
memory map files for different boards and cores. For example, sk2.3_em7d.x
is a memory map file for EM7D core of EM Starter Kit 2.3. You need to put that memory map
file to the current directory, rename it to memory.x
and use -Wl,-marcv2elfx
option while compiling your application. Please refer to Linker scripts and memory.x files for more details
about memory.x
files.
That is how we compile the application for EM7D core of EM Starter Kit 2.3:
cp -a toolchain/extras/dev_systems/sk2.3_em7d.x memory.x
arc-elf32-gcc -g -Wl,-marcv2elfx -specs=nosys.specs -mcpu=em4_dmips main.c -o main.elf
We use libnosys
(--specs=nosys.specs
) her to force standard IO functions
to do nothing - they will set errno = ENOSYS
and return -1 in most cases.
You need to use correct -mcpu
and other additional options for building your
application for particular board and core. You can find all necessary options
for any EM Starter Kit configuration in this table:
EM SK |
CPU |
Flags |
---|---|---|
v1 |
EM4 |
-mcpu=em4_dmips -mmpy-option=wlh5 |
EM6 |
-mcpu=em4_dmips -mmpy-option=wlh5 |
|
v2.0 |
EM5D |
-mcpu=em4 -mswap -mnorm -mmpy-option=wlh3 -mbarrel-shifter |
EM7D |
-mcpu=em4 -mswap -mnorm -mmpy-option=wlh3 -mbarrel-shifter |
|
EM7DFPU |
-mcpu=em4 -mswap -mnorm -mmpy-option=wlh3 -mbarrel-shifter -mfpu=fpuda_all |
|
v2.1 |
EM5D |
-mcpu=em4_dmips -mmpy-option=wlh3 |
EM7D |
-mcpu=em4_dmips -mmpy-option=wlh3 |
|
EM7DFPU |
-mcpu=em4_fpuda -mmpy-option=wlh3 |
|
v2.2 |
EM7D |
-mcpu=em4_dmips |
EM9D |
-mcpu=em4_fpus -mfpu=fpus_all |
|
EM11D |
-mcpu=em4_fpuda -mfpu=fpuda_all |
|
v2.3 |
EM7D |
-mcpu=em4_dmips |
EM9D |
-mcpu=em4_fpus -mfpu=fpus_all |
|
EM11D |
-mcpu=em4_fpuda -mfpu=fpuda_all |
Building an Application With Support of UART
Consider this application (assume that it’s saved in hello.c
):
#include<stdio.h>
int main()
{
printf("Hello, World!\n");
return 0;
}
You need to use emsk_em9d.specs
(for EM7D or EM9D) or emsk_em11d.specs
(for EM11D) specs files instead of nosys.specs
to enable support of UART.
It allows using standard C function for input and output: printf()
, scanf()
,
etc.
That is how we compile the application for EM7D core of EM Starter Kit 2.3:
cp -a toolchain/extras/dev_systems/sk2.3_em7d.x memory.x
arc-elf32-gcc -g -Wl,-marcv2elfx -specs=emsk_em9d.specs -mcpu=em4_dmips main.c -o main.elf
Running an application with OpenOCD
OpenOCD is used for connecting to development boards, running a GDB server and loading programs to the boards using GDB.
Starting OpenOCD
OpenOCD uses configuration files for describing different boards. OpenOCD is shipped with different configuration files for different EM Starter Kit versions:
snps_em_sk_v1.cfg
- for ARC EM Starter Kit v1.x.snps_em_sk_v2.1.cfg
- for ARC EM Starter Kit versions 2.0 and 2.1.snps_em_sk_v2.2.cfg
- for ARC EM Starter Kit version 2.2.snps_em_sk_v2.3.cfg
- for ARC EM Starter Kit version 2.3.snps_em_sk.cfg
- this is a configuration for ARC EM Starter Kit 2.0 and 2.1, preserved for compatibility.
Assume that EM Starter Kit 2.3 is used. If you’ve downloaded IDE bundle for
Linux then you can run OpenOCD this way (replace <ide>
by a path to
the directory of IDE bundle):
<ide>/bin/openocd -s <ide>/share/openocd/scripts -c 'gdb_port 49101' -f board/snps_em_sk_v2.3.cfg
If you’ve built and installed OpenOCD manually then you can run OpenOCD this way:
openocd -c 'gdb_port 49101' -f board/snps_em_sk_v2.2.cfg
If you’ve downloaded and installed IDE bundle for Windows then you can run OpenOCD this way:
openocd -s C:\arc_gnu\share\openocd\scripts -c "gdb_port 49101" -f board\snps_em_sk_v2.3.cfg
OpenOCD will be waiting for GDB connections on TCP port specified as an
argument to gdb_port
command (49101 in our case). If gdb_port
is not
passed then the default port 3333 is used. It’s recommended not to use a default
port since it may be occupied by another application. OpenOCD can be closed by CTRL+C.
Connecting GDB to OpenOCD
Write a sample application and save it to simple.c
:
int main()
{
int a = 1;
int b = 2;
int c = a + b;
return c;
}
Build the application for EM7D core of EM Starter Kit 2.3:
cp -a toolchain/extras/dev_systems/sk2.3_em7d.x memory.x
arc-elf32-gcc -g -Wl,-marcv2elfx -specs=nosys.specs -mcpu=em4_dmips main.c -o main.elf
Start OpenOCD as it described earlier and start GDB, connect to target and run it:
$ arc-elf32-gdb -quiet main.elf
# Connect. Replace 3333 with port of your choice if you changed it when starting OpenOCD
(gdb) target remote :3333
# Increase timeout, because OpenOCD sometimes can be slow
(gdb) set remotetimeout 15
# Load application into target
(gdb) load
# Go to start of main function
(gdb) tbreak main
(gdb) continue
# Resume with usual GDB commands
(gdb) step
(gdb) next
# Go to end of the application
(gdb) tbreak exit
(gdb) continue
# For example, check exit code of application
(gdb) info reg r0
Execution should stop at function exit
. Value of register r0
should be 3
.
Known issues and limitations
Bare metal applications has nowhere to exit, and default implementation of exit is an infinite loop. To catch exit from application you should set breakpoint at function
exit
like in the example.