# In-line Assembler in Lazarus on the Raspberry Pi

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
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;

asm
ldr r0, [r0]     // loads first integer of array into r0
end;

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
writeln('First integer in array: ', Int0);
writeln('Second integer in array: ', Int1);
WriteArray(MyTwoInts);
writeln('After writing to the array:');
writeln('First integer in array: ', Int0);
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]
cmp r1, #5
bne StartCol
sub r2, #5 // Right digit becomes 0
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
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
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
cmp r1, #20
bne StartLoopPush
mov r1, #0
StartLoopPop:
LDMFD r13!, {r12}  // pop r12
str r12, [r0, r1]  //  store r12 in array
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
```
Programming - a skill for life!

In-line assembler with Intel and AT&T syntax, addressing methods and encryption