You are viewing an older revision! See the latest version
Assembly Language
Calling an Assembly Language Function from C/C++¶
Here is a simple example showing an ARM assembly language routine called from C that blinks an LED. At the same time, the C API DigitalOut is used to blink a different LED to show the easier alternative in C. First in C/C++, the assembly language function, my_asm, must be declared external at the beginning of the C module. Then the assembly code can be called just like a C function using the C statement my_asm(value). In the code below, LED1 blinks using the assembly language function to write the new value to the bit, and LED4 blinks using the C API DigitalOut available in the mbed compiler.
Inline assembly code using _asm{…} inside a C source file is not currently supported in the mbed compiler, so the ARM assembly language source code must be placed in a separate *.s file. This file must be created or imported as a file into the project’s directory.
C_to_Asm.cpp
#include "mbed.h" // This program will blink LED1 and LED4 // using assembly language for LED1 and // API functions for LED4 // declare external assembly language function (in a *.s file) extern "C" int my_asm(int value); // declare LED outputs – let C set them up as output bits DigitalOut myled1(LED1); DigitalOut myled4(LED4); int main() { int value = 0; // loop forever while(1) { //call assembly language function to control LED1 my_asm(value); //API function to control LED4 myled4 = value; // flip value and wait value = ~ value; wait(0.2); } }
The ARM assembly language source file for this example is seen below. The AREA directive must appear on line 1 and directives cannot start in column 1. The entry point is my_asm setup as a label on the first instruction below and made available to C using the assembler directive EXPORT. The function’s argument, value, passed from the C compiler is placed in R0 and the assembly language routine is then called from C.
The assembly language code writes the new value to the GPIO bit connected to LED1. In the C API DigitalOut the compiler automatically determines the port address and bit number using the name LED1. From pinnames.h or the pin function table, LED1 is shown as being connected to GPIO port 1 bit 18. This could also be determined by checking the mbed module’s schematic to find the chip pin number connected to LED4. This information can then be used to find the address of the I/O registers used to control the pin by consulting Chapter 9 General Purpose Input/Output (GPIO) of the LPC1768 User Manual.
The code below writes the new bit out using GPIO Port 1’s FIOSET set or FIOCLR clear register along with a mask value used to select the correct bit. After finishing the write operation, the code returns to the C program code using the BX LR, Branch and exchange using link register. An assembly language source module must have the END directive on the last line.
Functions with more arguments will place the arguments in R0, R1, R2, R3 and then after four they will be passed on the stack. Keep in mind that there is additional overhead to call, pass arguments, and return from a function as opposed to inline code. Short function calls may not make sense once you consider this additional overhead.
ARM Assembly Language Example¶
my_asm.s
AREA asm_func, CODE, READONLY ; Export my_asm function location so that C compiler can find it and link EXPORT my_asm my_asm ; ; ARM Assembly language function to set LED1 bit to a value passed from C ; LED1 gets value (passed from C compiler in R0) ; LED1 is on GPIO port 1 bit 18 ; See Chapter 9 in the LPC1768 User Manual ; for all of the GPIO register info and addresses ; Pinnames.h has the mbed modules pin port and bit connections ; ; Load GPIO Port 1 base address in register R1 LDR R1, =0x2009C020 ; 0x2009C020 = GPIO port 1 base address ; Move bit mask in register R0 for bit 18 only MOV.W R2, #0x040000 ; 0x040000 = 1<<18 all "0"s with a "1" in bit 18 ; value passed from C compiler code is in R0 - compare to a "0" CMP R0, #0 ; value == 0 ? ; (If-Then-Else) on next two instructions using equal cond from the zero flag ITE EQ ; STORE if EQ - clear led 1 port bit using GPIO FIOCLR register and mask STREQ R2, [R1,#0x1C] ; if==0, clear LED1 bit ; STORE if NE - set led 1 port bit using GPIO FIOSET register and mask STRNE R2, [R1,#0x18] ; if==1, set LED1 bit ; Return to C using link register (Branch and change instruction set) BX LR END
The classical argument for assembly language programming is that will produce more efficient code. With today’s modern compilers this may still be true in some cases, but only for experienced assembly language programmers that can afford to spend the time optimizing code. The vast majority of programmers will have more efficient code using the compiler and will also be several times more productive since it takes fewer lines of C/C++ and these lines can also be coded and debugged faster to implement an application. In most cases, more speedup will typically be obtained by concentrating the development effort on the algorithms used in an application.
Some assembly language functions in application programs may still be used but only in a few critical places where low level routines interface with the device hardware or in a rare case where something is all but impossible with existing C/C++ features. Its use continues to decline every year as compilers improve and processors become faster and cheaper, at the same time as labor costs for software development increase. Compiler writers and processor hardware designers will of course always need to fully understand the processor’s assembly language, so students in those areas still need to learn assembly language.
While it is possible to try ARM assembly language programming on the mbed module, it is not the ideal environment to learn assembly language. A debugger that allows single stepping of instructions, breakpoints, and that can display register contents is really needed for anyone new to assembly language. An emulator that simulates the execution of assembly language programs on a desktop computer is really the ideal environment for learning assembly language.
References¶
ARM RealView Assembler Reference Guide
ARM assembly language textbook
LPC1768 processor data and user manuals
mbed LPC1768 module schematics
ARM Procedure Call Standard