1. ARM 64-bit Assembly Language

1. Introduction

1.1. Raspberry Pi OS has everything we need

If you have a Raspberry Pi 4 that runs its newest official 64-bit operating system called Raspberry Pi OS, then you do not need any other software. Your Raspberry Pi 4 already has the GCC compiler and the assembler. Assembler is a program that turns the code written in the assembly language into a program written in the machine language.

1.2. Code auto-grader

On this website, you can practice without writing the entire programs. You can write only parts of the code in the assembly language. This will be helpful in the beginning. The introductory exercises will ask for only few lines in the assembly language. The auto-grader will add the remaining commands, call the compiler and the assembler, and execute the obtained program.

1.3. Making entire programs

Once we are ready, we will move from this website's code auto-grader to your Raspberry Pi. We will start with very simple programs. They will be simpler than anything you have ever written. These first programs will not even print on the screen. They will only return an exit code. They will do that silently. We will have to use a separate command to ask the operating system to display the exit code.

Even these simplest programs would require us to go through a somewhat lengthy process. We will first need to write a program in the assembly language. After the program is written, we will have to use the gcc compiler to translate the program from the assembly language into the machine code. Then, we will need to execute the machine code. Finally, we will need to read the exit code that the program sent to the operating system.

2. Introduction to registers

2.1. Variables in high-level languages

Python, C, Java, C++, and other high-level languages had variables. We were allowed to use a lot of names for our variables. The best names were a, b, and c. However, we were also allowed to use the names that were not as good as these.

We were also allowed to use the commands such as a=7; b=27; c=37; and c=a+b;

The assembler doesn't let us use the variables. We also won't be allowed to write c=a+b;.

2.2. Registers in CPU

The central processing unit (known as CPU) does all the calculations. The CPU has several registers, and the calculations can be done only on numbers that are inside the registers.

We are not allowed to do operations on anything that is not a register.

Raspberry Pi 4 has 32 registers that can handle integer values. They are called

X0,   X1,   X2,   , ...,   X28,   X29,   LR,   SP
Each of them can hold a 64-bit integer. The registers LR and SP are special. They are called link register and stack pointer. They are very important and we will not touch them until we learn what they do. If we mess up with these registers before we learn what they are, then we will crash our programs with probability \(95\%\).

2.3. Arithmetic operations

We will now learn how to write the instructions that perform basic arithmetic operations. The arithmetic operations can be performed only on registers.

2.3.1. Addition

We can add values from two registers and store the result in the third. The following command will add the values inside X3 and X7 and store the result in X5.

ADD     X5,     X3,     X7

The instruction above is analogous to the instruction X5=X3+X7.

2.3.2. Subtraction

To perform the subtraction X5=X3-X7, we have to give the following instruction in assembly language:

SUB     X5,     X3,     X7

2.3.3. Multiplication

The multiplication X5=X3*X7 is achieved with the assembly instruction

MUL     X5,     X3,     X7

2.3.4. Division

The division cannot be done. The CPU does not have a way to divide two integers. We will have to write a function that performs integer division. That task is not easy at all. We will write such function later - once we learn how to write functions.

The CPU has an instruction for the division of real numbers, but not for the division of integers. We will not learn that instruction now because we are not ready to talk about real numbers yet. We will learn later that real numbers have to be stored in special registers that are different from X0, ..., X30. And we will have to learn about floating point representation of real numbers. These things have to wait.

3. Auto-grader practice

We know three instructions in the assembly language. They are ADD, SUB, and MUL This is enough for our first practice problems.

Here are few rules of the assembly language:

  • Each command must be in a separate line.
  • You are allowed to write comments. The rules for comments are pretty much the same as in C and C++. Multi-line comments are placed between /* and */. The GCC compiler is fine with single line comments, but other compilers may complain. It is best not to use single line comments.
  • Each of the fundamental instructions has 4 components: The name of the instruction, and the three registers. The three registers must be separated by commas. Optionally, the space characters (and/or tab characters) can be inserted before and after the commas. The name of the instruction and the name of the first register must be separated by one or more space characters (or tab characters).
  • Additional space characters do not have any effect. It is consider a good practice to put space characters (or tab symbols) in such a way that the assembly code looks like a matrix with 4 columns.
  • The assembly language is not case sensitive. Thus, add is the same as ADD. Also, x1 is the same as X1.

3.1. Problem with a solution

Please read the following problem and its solution. Then, have fun solving the problems in the auto-grader.

Problem 1. Write a code that calculates \(a\cdot b-c\) and stores the result in the register X0. The numbers \(a\), \(b\), and \(c\) are already placed in the registers X1, X2, and X3.

3.2. Practice

Problem 2.

Write a code that calculates \(a^2+b^2\) and stores the result in the register X0. The integers \(a\) and \(b\) are already placed in the registers X1 and X2.

You should only write the code that replaces the text /* ??? */ in the listing below.

/* *****************************************
  Autograder's program that reads the numbers a and b
  from the user input and stores them in the registers X1 and X2
*********************************************   */

   /* ??? */

/* *****************************************
  Autograder's program that prints the content of the register X0
*********************************************   */

Code editor

Problem 3.

Write a code that calculates \(a+bx+cx^2+dx^3\) and stores the result in the register X0. The integers \(a\), \(b\), \(c\), \(d\), and \(x\) are already placed in the registers X1, X2, X3, X4, and X5.

Hint: Try to use multiplication only 3 times! Once you spot the trick that can achieve this, you can write a very short code. The obtained code will not only be short, but also very fast. The multiplication is a much slower instruction than addition.

Code editor

4. Summary of basic facts about registers

This was an introductory section. We did not say everything that there is to be said about registers. Our focus was limited to only the most fundamental facts that are necessary for writing the first programs.

  • Each of the registers X0, X1, X2, ..., X29, LR, and SP has size 64 bits.
  • The register LR can also be accessed with the identifier X30. The register LR (or X30) is called link register. Do not put anything in this register before you learn about branch and link instructions. Otherwise, your program will crash in one way or another.
  • The register SP is called stack pointer. You cannot access it with the name X31. Do not put anything in this register before you learn about the program stack.
  • There are other integer registers called W0, W1, ..., W29, W30. They have size 32 bits, and they share the space with registers X0, ..., X30. The register Wi is the lower half of the register Xi. Never use the register W30.

5. MOV

The instruction

MOV     X1,     X2
copies the value from the register X2 and places it into the register X1.

6. Immediate values

The integers 0, 1, ..., 255 can be arguments of the arithmetic operations and of the MOV instruction. They are called immediate values.

An immediate value can only be the last argument of an instruction.

The instruction MOV is one of the most commonly used instructions in the assembly language. However, not every CPU architecture has the MOV instruction. When a CPU does not have MOV, then the assembler replaces the command MOV X1, X2 with ADD X1, X2, 0.

7. Practice problems

Problem 4.

Write a code that swaps the contents of the registers X1 and X2.

Code editor

Problem 5.

Write a code that swaps the contents of the registers X7 and X8 without using any other register.

Code editor