Skip to content

ARC64 Hello World example

Claudiu Zissulescu edited this page Jan 21, 2021 · 3 revisions

Getting the toolchain

You should have the ARC64 toolchain installed. The PATH environment variable needs to set and point to your toolchain installation.

A modulefile example can be as fallows:

#%Module1.0########################################################################
##
## ARC gcc module file
##
set ModulesVersion      "arc64"
proc ModulesHelp {} {
   global version

   puts stderr "   This module loads the ARC ELF toolchain"
   puts stderr "   Version $version"
   puts stderr ""
}

module-whatis         "arc_elf"

set arcinstall <my toolchain install path>
prepend-path PATH              $arcinstall/bin

conflict              arc_elf

Hello World example

Code hello.c:

#include <stdio.h>

void main (void)
{
  printf ("Hello Workd\n");
}

nSIM

Compiling for nSIM simulator using GNU hostlink I/O:

arc64-elf-gcc -O2 hello.c --specs=nsim.specs -o hello.x

Executing using nSIM simulator:

nsimdrv -on nsim_isa_enable_timer_0 -on nsim_isa_enable_timer_1 -off invalid_instruction_interrupt -off memory_exception_interrupt -on nsim_download_elf_sections -on nsim_emt -prop=nsim_isa_family=arc64 -p nsim_isa_div_rem_option=2 -p nsim_isa_mpy_option=3 -p nsim_isa_atomic_option=1 -p nsim_isa_shift_option=0 -p nsim_isa_bitscan_option=0 ./hello.x

nSIM/MDB

Compiling for nSIM/MDB usign MWDT hostlink I/O:

arc64-elf-gcc -O2 hello.c --specs=hl.specs -o hello.x

Executing using MDB:

mdb -arc64 -run -cl  hello.x

Executing using nSIM:

nsimdrv -on nsim_isa_enable_timer_0 -on nsim_isa_enable_timer_1 -off invalid_instruction_interrupt -off memory_exception_interrupt -on nsim_download_elf_sections -prop=nsim_isa_family=arc64 -p nsim_isa_div_rem_option=2 -p nsim_isa_mpy_option=3 -p nsim_isa_atomic_option=1 -p nsim_isa_shift_option=0 -p nsim_isa_bitscan_option=0 ./hello.x

QEMU

Compiling for QEMU simulator:

arc64-elf-gcc -O2 hello.c  --specs=qemu.specs -o hello.x

Executing using QEMU:

qemu-system-arc64 -M arc-sim -cpu arc64 -m 2G -nographic -no-reboot -monitor none -serial stdio -kernel hello.x

Linker scripts

The default script is sufficient for applications starting at address 0x0000000. The default heap is 20k, the default stack size 64k. The default linker script is providing the following heap/stack variables:

__start_heap
__end_heap
__stack
__stack_top

Using arc64-elf-nm:

arc64-elf-nm hello.x | grep "_heap"

The output will show the addresses of the heap start and end. The same we can do using stack matching pattern.

Changing the default stack or heap size can be done easily using the following linker commands:

-Wl,--defsym=__HEAP_SIZE=256m -Wl,--defsym=__STACK_SIZE=1024m

which will change the HEAP and the STACK accordingly. N.B. we can use either one, no need to increase stack size if sufficient. However, the programmer needs to make sure the stack and the heap are within the target memory range (he can use nm app as shown above).

If the default linker script doesn't satisfies the target needs one can use a custom script. Here it is a template:

MEMORY {
    ICCM  : ORIGIN = 0x00000000, LENGTH = 0xc0000000
    DCCM  : ORIGIN = 0xc0000000, LENGTH = 0x40000000
    }

  .ivt DEFINED (ivtbase_addr) ? ivtbase_addr : ORIGIN(ICCM) :
  {
    PROVIDE (__ivtbase_addr = .);
    KEEP (*(.ivt));
  }  > ICCM

  .text           :
  {
     . = ALIGN(4);
    KEEP (*(SORT_NONE(.init)))
    /* Start here after reset.  */
     . = ALIGN(4);
    KEEP (*crt0.o(.text.__startup))
    /* Remaining code.  */
     . = ALIGN(4);
    *(.text .stub .text.* .gnu.linkonce.t.*)
    /* .gnu.warning sections are handled specially by elf.em.  */
    *(.gnu.warning)
  }  > ICCM =0
  .fini           :
  {
    KEEP (*(SORT_NONE(.fini)))
    PROVIDE (__etext = .);
    PROVIDE (_etext = .);
    PROVIDE (etext = .);
  }  > ICCM =0
  .jcr   :
  {
    KEEP (*(.jcr))
  } > ICCM

  .rodata   :
  {
    *(.rodata) *(.rodata.*) *(.gnu.linkonce.r.*)
  } > ICCM

  .rodata1        : { *(.rodata1) } > ICCM

  __data_image = .;
  PROVIDE (__data_image = .);
  .data	  :
  {
     PROVIDE (__data_start = .) ;
    KEEP (*(.data))
    *(.data.* .gnu.linkonce.d.*)
    SORT(CONSTRUCTORS)
  }  > DCCM
  .ctors          :
  {
    KEEP (*crtbegin*.o(.ctors))
    KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors))
    KEEP (*(SORT(.ctors.*)))
    KEEP (*(.ctors))
  }  > DCCM
  .dtors          :
  {
    KEEP (*crtbegin*.o(.dtors))
    KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors))
    KEEP (*(SORT(.dtors.*)))
    KEEP (*(.dtors))
  }  > DCCM
  .sbss           :
  {
    PROVIDE (__sbss_start = .);
    PROVIDE (___sbss_start = .);
    *(.dynsbss)
    *(.sbss .sbss.* .gnu.linkonce.sb.*)
    *(.scommon)
    PROVIDE (__sbss_end = .);
    PROVIDE (___sbss_end = .);
  }  > DCCM
  .sbss2          : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }  > DCCM
  .bss            :
  {
    *(.dynbss)
    *(.bss .bss.* .gnu.linkonce.b.*)
    *(COMMON)
    . = ALIGN(32 / 8);
   _end = .;
   PROVIDE (end = .);
  }  > DCCM

  .noinit  :
  {
    *(.noinit*)
    . = ALIGN(32 / 8);
     PROVIDE (__start_heap = .) ;
  }  > DCCM
   PROVIDE (__stack_top = (ORIGIN (DCCM) + LENGTH (DCCM) - 1) & -4);
   PROVIDE (__end_heap = ORIGIN (DCCM) + LENGTH (DCCM) - 1);
}