GNU tools for ARC-V

The GNU toolchain for ARC-V processors is a pre-built and verified distribution of a GCC-based set of tools for building applications targeting supported ARC-V processors.

This toolchain is built on the pillars of proven and widely used open-source components such as GCC, Binutils, GDB, and Newlib. While many pre-built GCC-based toolchains are available around the Internet, and it is reasonably easy to build your own, the ARC GNU toolchain is prepared specifically to produce the best possible results for ARC processors. It also makes sure the results produced are reliable in all supported environments.

GNU Toolchain for ARC-V Processors v2023.12

This is the 2023.12 version of the GNU Toolchain for Synopsys ARC-V Processor IP. This release introduces support for the ARC-V RMX and RHX processors series based on the RISC-V instruction-set architecture.

More information about these processors can be found on Synopsys website:

Note

This release of the ARC GNU tools doesn’t include prebuilt toolchains for ARC Classic processor families. Users of ARC 600, ARC 700, ARC EM, ARCv2 HS (HS3x and HS4x) and ARCv3 HS (HS5x and HS6x) should keep using ARC GNU Tools 2023.09 (latest version).

New Features and Enhancements

Support for RISC-V based ARC-V RMX and RHX Processors

  • In this release the following RISC-V extensions are supported: Zba, Zbb, Zbs, Zdinx, Zfinx, Zicbom, Zicbop, and Zicboz.

  • Support for ARC-V RMX and RHX processors:

    • Instruction scheduling tuning for ARC-V RMX-100 (-mtune=rmx100) and RMX-500 (-mtune=rmx500)

    • Instruction fusion for the ARC-V RHX series (-mtune=rhx)

    • Implementation of the code-size reduction extensions Zcb and Zcmp

  • As this is the first release of prebuilt GNU tools with ARC-V support, some functionality might have issues, some processor features might not yet be fully supported, and performance might be lower than expected performance of the final product.

Binary Distribution

  • Supported host operating systems: Windows 10/11 64-bit, Ubuntu 18.04.x, 20.04.x, CentOS/RHEL 7.x

  • Prebuilt bare-metal toolchains for 64-bit Windows & Linux hosts; see table with references and list of artifacts.

Toolchain Components

  • GCC 13.2 with ARC patches

  • Binutils pre-2.41 with ARC patches

  • GDB 12.1 with ARC patches

  • Newlib 4.3.0 with ARC patches

    • Updated sources of 4.3.0 release; see Newlib release announcement.

    • Improved start-up code to initialize GP (global pointer), SP (stack pointer), clear .bss section, and similar enhancements.

    • Provided custom linker command file for use with fast on-chip memories (DCCM and ICCM).

Known Issues

There are no known issues for this release so far.

Getting Help

A Getting Started manual covering all aspects of the ARC-V family of processors is available here: https://foss-for-synopsys-dwc-arc-processors.github.io/arc-v-getting-started.

Also visit the GitHub discussions link for a community forum tailored to ARC-V processors. To report issues and enhancement requests, use GitHub issues (if you are not sure, start with discussions, since a discussion can always be converted into an issue).

Prebuilt Toolchains Available for Download

Archive SHA-256 checksums are:

4e555c1b214eb97fd3bf9e1ffa43d69a0d274deb295fec66bdfdebef714b7bf7 arc_gnu_2023.12_prebuilt_riscv64_elf_le_win_install.tar.bz2
9dedb6e496e52a45ce536c9a1970a44401319c42ea17b7b8f6655b6204b9b444 arc_gnu_2023.12_prebuilt_riscv64_elf_le_linux_install.tar.bz2

Command-Line Reference

Because the ARC-V GNU toolchain is built on top of standard components such as GCC, Binutils, and GDB, all functionality of these tools stays in place and can be studied in detail in the corresponding manuals:

On top of the functionality that comes with the standard releases of these tools, the ARC GNU toolchain adds some ARC-V specific options:

The ARC-V GNU compiler has support for the ARC-V RMX-100, RMX-500, and RHX CPU families. To enable compiler optimizations for those CPU families you must use certain -mtune options. The valid -mtune options are:

  • rmx100 for the ARC-V RMX-100 family

  • rmx500 for the ARC-V RMX-500 family

  • rhx for the ARC-V RHX family

The architecture options used by the ARC-V RMX-100, RMX-500 and RHX families are -march=rv32im_zba_zbb_zbs_zicsr_zca_zcb_zcmp -mabi=ilp32.

ARC-V .specs File

The new arcv.specs file uses a custom starting routine based on the original crt0.S with a special linker command file.

The latter is highly configurable, introducing four new linker defines:

  • txtmem_addr if defined sets the ICCM start address; otherwise the ICCM start address is set to 0x0

  • txtmem_len if defined sets the ICCM length; otherwise the length is set to 128K

  • datamem_addr if defined sets the DCCM start address; otherwise the DCCM start address is set to 0x8000_0000

  • datamem_len if defined sets the DCCM length, otherwise the length is set to 128K

Where:

  • ICCM is usually flash memory or ROM.

  • DCCM is usually SRAM.

  • You can set a linker define as follows (using the GCC driver): For example: -Wl,-defsym=datamem_addr=0x10000

This spec file can be used with other spec files too. For example, using semihosting: --specs=semihost.specs  --specs=arcv.specs.

The First Sample Application

Consider the following sample application:

#include <stdio.h>

extern void init_semihosting ();

int main(void) {
   init_semihosting();
   printf("Hello world!\n");
   return 0;
}

Build and Run a Simple Application for Synopsys nSIM

The following commands can be used for compiling the sample for later execution in the nSIM simulator:

  • For an ARC-V RMX-100 processor:

    $ riscv64-elf-gcc --specs=semihost.specs --specs=arcv.specs -mabi=ilp32 \
                      -mtune=rmx100 -march=rv32im_zba_zbb_zbs_zca_zcb_zcmp_zicsr \
                      -T arcv.ld test.c -o a.out
    
  • For an ARC-V RMX-500 processor:

    $ riscv64-elf-gcc --specs=semihost.specs --specs=arcv.specs -mabi=ilp32 \
                      -mtune=rmx500 -march=rv32im_zba_zbb_zbs_zca_zcb_zcmp_zicsr \
                      -T arcv.ld test.c -o a.out
    
  • For an ARC-V RHX processors:

    $ riscv64-elf-gcc --specs=semihost.specs --specs=arcv.specs -mabi=ilp32 \
                      -mtune=rhx -march=rv32im_zba_zbb_zbs_zca_zcb_zcmp_zicsr \
                      -T arcv.ld test.c -o a.out
    

After building, use the following command line to run the sample in nSIM:

$ nsimdrv -prop=nsim_isa_family=rv32 \
  -prop=nsim_isa_ext=-all.i.zicsr.zifencei.zihintpause.b.zca.zcb.zcmp.zcmt.a.m.zbb \
  -prop=nsim_semihosting=1 -off=enable_exceptions a.out

Hello world!

For more details on use of the Synopsys nSIM simulator, see the section dedicated to it here: nSIM and NCAM.

Build and Run a Simple Application for QEMU

It is best to use the latest official QEMU version for the following exercises. As of today, it’s v8.2; see release notes here https://wiki.qemu.org/ChangeLog/8.2. The sources are on GitLab (https://gitlab.com/qemu-project/qemu) or in the official GitHub mirror (https://github.com/qemu/qemu).

Note

To get the latest version of QEMU on your system it might be much easier to build it from sources rather than trying to find a pre-built version which suits your host type and operating system.

Instructions for building on Linux are on QEMU’s Wiki: https://github.com/qemu/qemu

First you need to install required additional packages, which depend on the Linux distribution used on the host. For example for Ubuntu 20.04 the following needs to be done:

$ apt-get install build-essential git libglib2.0-dev libfdt-dev \
  libpixman-1-dev zlib1g-dev ninja-build python3-venv

After installation of prerequisites you can download sources, configure, and build in the following way:

# Clone v8.2.0 from GitHub repository
$ git clone --depth 1 --branch v8.2.0 git@github.com:qemu/qemu.git

# Configure project for build selecting only RISCV32 full system emulation,
$ ./configure --target-list=riscv32-softmmu

# Build QEMU
$ make

After the build is complete qemu-system-riscv32 is placed in the build folder, which you can add to the PATH environment variable for convenience, and use the short binary name instead of the full path.

The following commands can be used for compiling the sample for later execution in QEMU. Basically the same compiler options are used, except that you need to make sure DDR memory is used and the .text section starts in the DDR beginning at 0x8000_0000, where the board jumps on start automatically. For that, you need to override two linker symbols otherwise defined in ARC-V’s default linker script arcv.ld: txtmem_addr and datamem_addr.

Then the command lines look like this:

  • For an ARC-V RMX-100 processor:

    $ riscv64-elf-gcc --specs=semihost.specs --specs=arcv.specs -mabi=ilp32 \
                      -mtune=rmx100 -march=rv32im_zba_zbb_zbs_zca_zcb_zcmp_zicsr \
                      -Wl,-defsym=txtmem_addr=0x80000000 -Wl,-defsym=datamem_addr=0x80100000 \
                      -T arcv.ld test.c -o a.out
    
  • For an ARC-V RMX-500 processor:

    $ riscv64-elf-gcc --specs=semihost.specs --specs=arcv.specs -mabi=ilp32 \
                      -mtune=rmx500 -march=rv32im_zba_zbb_zbs_zca_zcb_zcmp_zicsr \
                      -Wl,-defsym=txtmem_addr=0x80000000 -Wl,-defsym=datamem_addr=0x80100000 \
                      -T arcv.ld test.c -o a.out
    
  • For an ARC-V RHX processor:

    $ riscv64-elf-gcc --specs=semihost.specs --specs=arcv.specs -mabi=ilp32 \
                      -mtune=rhx -march=rv32im_zba_zbb_zbs_zca_zcb_zcmp_zicsr \
                      -Wl,-defsym=txtmem_addr=0x80000000 -Wl,-defsym=datamem_addr=0x80100000 \
                      -T arcv.ld test.c -o a.out
    

After building, use the following command line to run the sample in QEMU:

$ qemu-system-riscv32 -semihosting -nographic -machine virt -cpu rv32 -bios none -kernel a.out

Hello world!

For more details on use of the QEMU simulator, see the official documentation here: https://www.qemu.org/docs/master/.

Debugging a Simple Application

With the Synopsys LLDB Debugger and Visual Studio Code IDE

For detailed information on how to debug an application with the Synopsys LLDB Debugger and Visual Studio Code IDE, see the following section: The MetaWare Development Toolkit.

With QEMU and GDB

You can debug an application that is being run on QEMU with help of the built-in GDB server of QEMU. On the QEMU side, you need to enable the GDB sever and optionally instruct the QEMU not to start the application execution automatically, but instead wait for user input. For that you need to pass -s -S commands to qemu-system-riscv32 so that the full command-line looks like this:

$ qemu-system-riscv32 -semihosting -nographic -machine virt -cpu rv32 -bios none -kernel a.out -s -S

Then you can attach the GDB client and start debugging. Do the following in a separate console:

$ riscv64-elf-gdb a.out

(gdb) target remote :1234
Remote debugging using :1234
0x00001000 in ?? ()

(gdb) b main
Breakpoint 1 at 0x800000b4: file ~/test.c, line 10.

(gdb) continue
Continuing.

Breakpoint 1, main () at ~/test.c:10
10              init_semihosting();

(gdb) c
Continuing.
[Inferior 1 (process 1) exited normally]

Note that the first location where the CPU is waiting for commands is 0x0000_1000. It’s a virt board reset vector location; see https://elixir.bootlin.com/qemu/v8.2.0/source/hw/riscv/boot.c#L396. It is not possible to suppress execution of that reset vector code as it’s an essential part of the QEMU board (think of it as a boot-ROM). You can only bypass it if you load the target executable from the GDB client with the load command. Then execution starts from the loaded application entry point.

Testing Specific RISC-V Extensions

One of the benefits of RISC-V ISA is its extensibility. As a matter of fact, only a handful of instructions form the minimally required base. But the most interesting part is in utilizing application-specific extensions, which let you achieve benefits in certain situations.

In embedded and especially deeply embedded applications, one of the key objectives is to keep the memory footprint of the target application as tiny as possible. And the RISC-V Zc* extensions help to achieve exactly that. This section demonstrates a couple of those extensions in action. See also the documentation and related information on each extension on the corresponding GitHub resource here: https://github.com/riscv/riscv-code-size-reduction.

Zcmp Extension

Consider the following code snippet:

$ cat t01.c

void test (void) {
    asm volatile (""
             :
             :
             : "s0", "s1", "s2", "s3",
               "s4", "s5", "s6", "s7",
               "s8", "s9", "s10", "s11");
}

Here is a generated assembly listing targeting the Zcmp extension:

$ riscv64-unknown-elf-gcc -march=rv32im_zcmp -mabi=ilp32 t01.c -S -O1 -o -

    .file   "t01.c"
    .option nopic
    .attribute arch, "rv32i2p1_m2p0_zca1p0_zcmp1p0"
    .attribute unaligned_access, 0
    .attribute stack_align, 16
    .text
    .align  1
    .globl  test
    .type   test, @function
test:
     cm.push {ra, s0-s11}, -64
     cm.popret       {ra, s0-s11}, 64
     .size   test, .-test
     .ident  "GCC: (RISC-V elf toolchain - build 6278) 13.2.0"

Note the generated cm.push and cm.popret instructions, which confirm that the compiler is capable of using the extension.

Zcb Extension

Another RISC-V extension that is easy to see in action also comes from the code-size-reduction group: Zcb. Consider the following C function:

$ cat t03.c

int test (int a, int b) {
    return a + b;
}

Now compile and disassemble it:

$ riscv64-elf-gcc -march=rv32im_zca_zcb -mabi=ilp32 t03.c -c -O1
$ riscv64-unknown-elf-objdump -d t03.o

t03.o:     file format elf32-littleriscv


Disassembly of section .text:

00000000 <test>:
   0:   952e                    add     a0,a0,a1
   2:   8082                    ret

Note the short 16-bit encoding of the add instruction. Without use of Zc extensions, compiler generates a full 32-bit encoding as in the example below.

$ riscv64-elf-gcc -march=rv32im -mabi=ilp32 t03.c -c -O1
$ riscv64-unknown-elf-objdump -d t03.o

t03.o:     file format elf32-littleriscv


Disassembly of section .text:

00000000 <test>:
   0:   00b50533                add     a0,a0,a1
   4:   00008067                ret