Running D on bare metal ARM

By combining the GDC ARM compiler with the stripped runtime concept we used in Chapter 11, D for Kernel Coding, we can also run D on a bare metal ARM board. Going from this concept to a working program will take a lot of work, but we will get started with a "hello world" program.

Getting ready

Get an emulator such as QEMU and the GDC cross-compiler targeting ARM. The same cross-compiler for Raspberry Pi that we used previously will work here too. Also, copy the minimal object.d from Chapter 11, D for Kernel Coding, to a new folder for the ARM project.

How to do it…

To run D on bare metal ARM, we need to execute the following steps:

  1. Create a startup.s file that sets up the stack, calls the D function, and then endlessly loops. The code is as follows:
    .global _start
    _start:
      LDR sp, =stack_top  @ prepare a stack
      BL _d_run_main      @ call our D entry point
      B .                 @ endlessly loop
  2. Create a linker script, linker.ld, which puts the startup code at the beginning of the file and reserves stack space. The code is as follows:
    ENTRY(_start)
    SECTIONS
    {
     . = 0x10000;
     .startup . : { startup.o(.text) }
     .text : { *(.text) }
     .data : { *(.data) }
     .bss : { *(.bss COMMON) }
     . = ALIGN(8);
     . = . + 0x1000; /* 4kB of stack memory */
     stack_top = .;
    }
  3. Modify object.d to add an ARM version which calls _Dmain and loops with regular D code instead of inline assembly. The code is as follows:
    void _d_run_main() {
            version(ARM) {
                    _Dmain();
                    while(true) {}
           }
    }
  4. Write a hello.d file that says hello by writing to the serial port's memory address. The code is as follows:
    enum serialPort = cast(shared(uint)*) 0x101f1000;
    
    void printToSerialPort(string s) {
            foreach(c; s)
                    *serialPort = c;
    }
    
    void main() {
            printToSerialPort("Hello world from D!
    ");
    }
  5. Create a Makefile that assembles startup.s, compiles object.d and hello.d with exceptions disabled and the release mode flag turned on, links it together with the linker script, and then converts the output to a binary image. The code is as follows:
    all:
            arm-gdcproject-linux-gnueabi-as -mcpu=arm926ej-s -g startup.s -o startup.o
            arm-gdcproject-linux-gnueabi-gdc -frelease -fno-exceptions -c -mcpu=arm926ej-s -g object.d -o object.o
            arm-gdcproject-linux-gnueabi-gdc -frelease -fno-exceptions -c -mcpu=arm926ej-s -g hello.d -o hello.o
            arm-gdcproject-linux-gnueabi-ld -T linker.ld hello.o startup.o object.o -o hello.elf
            arm-gdcproject-linux-gnueabi-objcopy -O binary hello.elf hello.bin
  6. Run the program using qemu-system-arm -M versatilepb -m 128M -kernel hello.bin –sdl.

In the serial console view of QEMU (press Ctrl + Alt + 3 to switch to it), you'll see the "hello world" message.

How it works…

Bare metal code for ARM computers follows the same basic principles as for x86 PCs, and the D code to get you started is substantially similar. The biggest difference is the use of the GDC compiler instead of dmd, because GDC can generate code for ARM targets and dmd cannot.

GDC also does not support inline assembly syntax of dmd or naked functions (though the gcc backend does support naked functions for ARM targets, so support for that may be added later). Instead, GDC supports inline assembly based on the gcc syntax, which uses strings of assembly code with input, output, and destroyed register specifiers.

Other significant differences between dmd and GDC will only become apparent if exceptions are enabled, and since we disabled them for the minimal runtime, we didn't have to worry about that here.

Of course, x86 and ARM hardware is significantly different in regards to details such as memory mapped addresses, but the principle is the same: use a pointer to the correct address to communicate. Here, we used a pointer to the UART0 serial port and wrote our string to it, saying hello.

See also

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.135.198.174