Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
D Cookbook

You're reading from   D Cookbook Discover the advantages of programming in D with over 100 incredibly effective recipes with this book and ebook.

Arrow left icon
Product type Paperback
Published in May 2014
Publisher
ISBN-13 9781783287215
Length 362 pages
Edition Edition
Arrow right icon
Author (1):
Arrow left icon
Adam Ruppe Adam Ruppe
Author Profile Icon Adam Ruppe
Adam Ruppe
Arrow right icon
View More author details
Toc

Table of Contents (21) Chapters Close

D Cookbook
Credits
Foreword
About the Author
About the Reviewers
www.PacktPub.com
Preface
Core Tasks FREE CHAPTER Phobos – The Standard Library Ranges Integration Resource Management Wrapped Types Correctness Checking Reflection Code Generation Multitasking D for Kernel Coding Web and GUI Programming Addendum Index

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!\n");
    }
  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

lock icon The rest of the chapter is locked
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime
Banner background image