Minimal semihosted ARM Cortex-M "Hello World"

From D Wiki
Jump to: navigation, search

The following is an extremely minimal, semihosted "Hello World" D program for ARM Cortex-M processors.

Goals

  • Verify ARM Cortex-M toolchain (compiler-->linker-->debugger)
  • Demonstrate that the D runtime and D standard library are not mandatory
  • Demonstrate that linking to C code is not necessary
  • Demonstrate that all required assembly code can be done within D
  • Provide a starting point, with a low barrier to entry, for developers to begin testing the toolchain, porting the D runtime and libraries to the ARM Cortex-M platform, and programming their ARM Cortex-M software in D

Tools

  • (host computer) Arch Linux 64-bit
  • (compiler) LDC with ARM backend
  • (linker & debugger) GNU Tools for GNU Tools for ARM Embedded Processors 4.7-2013-q3
  • (GDB server) OpenOCD 0.7.0
  • (JTAG emulator) JTAG-lock-pick Tiny 2

The Code

Program Source code (start.d)

module start;

import ldc.llvmasm;

extern(C) __gshared void * _Dmodule_ref;

//Must be stored as second 32-bit word in .text section
immutable void function() ResetHandler = &OnReset;

void SendCommand(int command, void* message)
{
  __asm
  (
    "mov r0, $0;
     mov r1, $1;
     bkpt #0xAB",
     "r,r,~{r0},~{r1}",
     command, message
   );
}

void OnReset()
{
  while(true)
  {
    // Create semihosting message message
    uint[3] message =
      [
	2, 			      //stderr
	cast(uint)"hello\r\n".ptr,    //ptr to string
	7                             //size of string
      ];

    //Send semihosting command
    SendCommand(0x05, &message);
  }
}

Compile with:

ldc2 -march=thumb -mcpu=cortex-m4 -noruntime -nodefaultlib -c start.d

Linker Script(link.ld)

MEMORY
{
  CCRAM    (rxw) : ORIGIN = 0x10000000, LENGTH =   64k
  SRAM     (rxw) : ORIGIN = 0x20000000, LENGTH =  128k
  FLASH    (rx)  : ORIGIN = 0x08000000, LENGTH = 1024k
}

_stackStart = ORIGIN(CCRAM) + LENGTH(CCRAM);

SECTIONS
{
  .text :
  {
    LONG(_stackStart);              /* Initial stack pointer */
    KEEP(start.o(.data.rel.ro))     /* Internet vector table */

    /* the code */
    *(.text)
    *(.text*)

    /* for "hello\r\n" string constant */
    . = ALIGN(4);
    *(.rodata)
    *(.rodata*)
  }>FLASH

  /* Need .data, .bss, .ctors and probably more as program becomes
     More complex */
}

Link with:

arm-none-eabi-ld -T link.ld --gc-sections start.o -o start.elf

Execution

Start OpenOCD:

openocd -f interface/jtag-lock-pick_tiny_2.cfg -f target/stm32f4x.cfg

Start GDB:

arm-none-eabi-gdb start.elf

In GDB, attach to OpenOCD, reset the hardware, load the executable, and begin execution

target remote localhost:3333
monitor arm semihosting enable
monitor reset halt
load
monitor reset init
continue

Output (in OpenOCD window):

hello
hello
...

TODO

  • Modify this software to compile for both GDC and LDC