In-line Assembler in Lazarus on the Raspberry Pi
[First Demo][Shifts and Loop][Local Variable][Simple Array][2D Array][String][Subroutine][Stack]
See in our Translators tutorial an introduction to ARM assembler and also how we have converted Jack Crenshaw's TINY compiler to generate ARM assembly code. Using version 0.9.30.4-6 of Lazarus on Debian Linux on the Raspberry Pi, we developed these introductory demonstrations (with copious comments).
When arguments are passed to procedures, registers r0 to r3 hold the addresses of the first four arguments.
Demonstration of Addition, Subtraction, Multiplication and Branching
program AsmLazPiDemo1; var MyResult: Integer; // An assembler function returns the last value of r0 function asmfn: integer; assembler; label equality; asm mov r0, #0 // initialises r0 to 0 add r0, #5 // adds immediate operand 5 to r0 add r0, #2 // adds immediate operand 2 to r0 sub r0, #4 // subtracts immediate operand 4 from r0 mov r1, r0 // copies value in r0 (3) to r1 add r0, r1 // adds r1 to r0, storing sum (6) in r0 mov r2, r0 // copies contents of r0 (6) to r2 cmp r0, #3 // compares r0 with immediate operand 3 ... beq equality // and branches to label "equality" if equal (which it is not) mul r0, r1, r2 // multiplies r1 (3) by r2 (6) and stores product in r0 equality: end; begin MyResult := asmfn; writeln(MyResult); end.
Output: 18
Demonstration of Shifts and Loop
program AsmLazPiDemo2; var ShiftResult, LoopResult: Integer; function ShiftLeft(x, s: integer): integer; assembler; asm lsl r0, r1 // x logical shift left by s places end; function ShiftRight(x, s: integer): integer; assembler; asm lsr r0, r1 // x logical shift right by s places end; function LoopTest(iterations: integer): integer; assembler; // http://www.davespace.co.uk/arm/introduction-to-arm/conditional.html label loop; asm mov r1, r0 // initialises r1 to iterations mov r0, #0 // initialises r0 to 0 loop: add r0, r1 // adds r1 to r0, storing result in r0 subs r1, #1 // subtracts 1 from r1 and sets flags bne loop // loops if result is not zero end; begin ShiftResult := ShiftLeft(4, 1); writeln('Result of shifting binary 100 left by one place: ', ShiftResult); ShiftResult := ShiftRight(64, 2); writeln('Result of shifting binary 1000000 right by two places: ', ShiftResult); LoopResult := LoopTest(10); writeln('Addition of numbers from 10 down to 1: ', LoopResult); end.
Output:
/home/pi/laz/asm/AsmLazPiDemo2 Result of shifting binary 100 left by one place: 8 Result of shifting binary 1000000 right by two places: 16 Addition of numbers from 10 down to 1: 55
Demonstration of Local Variable
program AsmLazPiDemo3; var LocalVarResult: Integer; function LocalVar: integer; assembler; var a: integer; asm mov r1, #13 // initialises r1 with 13 str r1, a // stores r1 contents (13) in local variable a ldr r0, a // loads contents of a into r0 end; begin LocalVarResult := LocalVar; writeln('Contents of local variable a: ', LocalVarResult); end.
Output:
/home/pi/laz/asm/AsmLazPiDemo3 Contents of local variable a: 13 -------------------------------------------------- Press enter
Demonstrations of Array Processing
program AsmLazPiDemo4; type TTwoInts = array[0..1] of integer; var MyTwoInts: TTwoInts = (4, 1); Int0, Int1: integer; function ReadArray0(x: TTwoInts): integer; assembler; asm ldr r0, [r0] // loads first integer of array into r0 end; function ReadArray1(x: TTwoInts): integer; assembler; asm ldr r0, [r0, #4] // loads second integer of array into r0 end; procedure WriteArray(x: TTwoInts); assembler; asm mov r1, #42 str r1, [r0] // stores 42 as first integer of array mov r1, #84 str r1, [r0, #4] // stores 84 as second integer of array end; begin Int0 := ReadArray0(MyTwoInts); writeln('First integer in array: ', Int0); Int1 := ReadArray1(MyTwoInts); writeln('Second integer in array: ', Int1); WriteArray(MyTwoInts); writeln('After writing to the array:'); Int0 := ReadArray0(MyTwoInts); writeln('First integer in array: ', Int0); Int1 := ReadArray1(MyTwoInts); writeln('Second integer in array: ', Int1); end.
Output:
/home/pi/laz/asm/AsmLazPiDemo4 First integer in array: 4 Second integer in array: 1 After writing to the array: First integer in array: 42 Second integer in array: 84
program AsmLazPiDemo5; type TTable = array[1..4, 1..5] of byte; var Table: TTable; Row, Col: integer; procedure PopulateArray(arr: TTable); assembler; label StartRow, StartCol; asm mov r2, #0 // r2 to contain current byte mov r3, #0 // zero based row count StartRow: add r2, #10 // Left digit is row number (see output) mov r1, #0 // zero based col count StartCol: add r2, #1 //Right digit is column number. // Use indirect indexed addressing to put cell value in table str r2, [r0, r1] add r1, #1 cmp r1, #5 bne StartCol add r3, #1 sub r2, #5 // Right digit becomes 0 add r0, #5 //Change the address in the base register r0 cmp r3, #4 bne StartRow end; begin PopulateArray(Table); for row := 1 to 4 do begin for col := 1 to 5 do write(Table[Row,Col], ' '); writeln; end; end.
Output:
/home/pi/laz/asm/AsmLazPiDemo5 11 12 13 14 15 21 22 23 24 25 31 32 33 34 35 41 42 43 44 45
Demonstration of String Processing
program AsmLazPiDemo6; var MyString: ShortString = 'abcdefghij'; MyStringLength: byte; procedure ProcessString(str: ShortString); assembler; asm ldr r1, [r0, #1] // loads first ASCII code into r1 sub r1, #32 // converts first letter to upper case str r1, [r0, #1] // and stores it end; function StringLength(str: ShortString): integer; assembler; asm ldr r0, [r0] // loads first byte (string length) into r0 end; begin ProcessString(MyString); writeln(MyString); MyStringLength := StringLength(MyString); writeln('Length of string: ', MyStringLength); end.
Output:
/home/pi/laz/asm/AsmLazPiDemo6 Abcdefghij Length of string: 10
Demonstration of Subroutine
program AsmLazPiDemo7; var Sum: integer; function AddPowers(num1, exp1, num2, exp2: integer): integer; assembler; label pow, finish; asm mov r4, r0 // copies num1 into r4 mov r7, r0 // copies num1 into r7 mov r5, r1 // copies exp1 into r5 bl pow // calls subroutine mov r0, r4 // saves result in r0 // repeat for num2 and exp2 mov r4, r2 mov r7, r2 mov r5, exp2 bl pow add r0, r4 // adds current result b finish // then ends pow: mul r4, r7 // multiplies r7 by r4, storing result in r4 sub r5, #1 // subtracts 1 from r5 cmp r5, #1 // compares r5 with 1 bne pow // loops if r5 is not equal to 1 bx lr // returns from subroutine finish: end; begin Sum := AddPowers(2, 3, 3, 4); // adds 2^3 to 3^4 writeln('2^3 + 3^4 = ', Sum); end.
Output:
/home/pi/laz/asm/AsmLazPiDemo7 2^3 + 3^4 = 89
Stack Demonstration
This uses store multiple (STM) and load multiple (LDM) instructions to push and pop a single register. (The push and pop instructions are unavailable in the current in-line assembler).
program AsmLazPiDemo8; type TIntArray5 = array[1..5] of integer; var MyInts: TIntArray5 = (2, 4, 6, 8, 10); i: integer; procedure Reverse(arr: TIntArray5); assembler; label StartLoopPush, StartLoopPop; asm mov r1, #0 StartLoopPush: ldr r12, [r0, r1] // load integer from array into r12 STMFD r13!, {r12} // push r12 add r1, #4 cmp r1, #20 bne StartLoopPush mov r1, #0 StartLoopPop: LDMFD r13!, {r12} // pop r12 str r12, [r0, r1] // store r12 in array add r1, #4 cmp r1, #20 bne StartLoopPop end; begin Reverse(MyInts); for i := 1 to 5 do write(MyInts[i] : 3); writeln; end.
Output:
/home/pi/laz/asm/AsmLazPiDemo8 10 8 6 4 2