$24
This is an introductory exercise in using the ARM* Cortex* A9 processor that is included in Intel’s Cyclone R V SoC devices. The exercise uses the DE1-SoC Computer, which is implemented as a circuit that is downloaded into the FPGA device on the board. We will show how to develop programs written in the ARM assembly language that can be executed on your DE1-SoC board. You will use the Intel FPGA Monitor Program software to compile, load, and run the application programs.
To perform this exercise you need to be familiar with the ARM processor architecture and its assembly language. An overview of the ARM processor that is included in Intel’s SoC devices can be found in the tutorial Introduction to the ARM Processor. You also need to be familiar with the Monitor Program for developing ARM programs, which is described in the tutorial Intel FPGA Monitor Program Tutorial for ARM. Both tutorials are available in Intel’s FPGA University Program web site. The Monitor Program tutorial can also be accessed by selecting Help
Tutorial within the Monitor Program software.
Part I
In this part you will use the Intel FPGA Monitor Program to set up an ARM software development project.
Perform the following:
Make sure that the power is turned on for the DE1-SoC board.
Open the Intel FPGA Monitor Program software, which leads to the window in Figure 1.
To develop ARM software code using the Monitor Program it is necessary to create a new project. Select File New Project to reach the window in Figure 2. Give the project a name and indicate the folder for the project; we have chosen the project name part1 in the folder Exercise1nPart1, as indicated in the figure. Use the drop-down menu shown in Figure 2 to set the target architecture to the ARM Cortex-A9 processor. Click Next, to get the window in Figure 3.
Now, you can select your own custom computer system (if you have one) or a pre-designed (by Intel) system. As shown in Figure 3 select the DE1-SoC Computer. Once you have selected the computer system the display in the window will now show where files that implement the chosen system are located. Click Next.
1
Figure 1: The Intel FPGA Monitor Program window.
Figure 2: Specify the folder and the name of the project.
2
Figure 3: Specification of the system.
In the window in Figure 4 you can specify the type of application programs that you wish to run. They can be written in either assembly language or the C programming language. Specify that an assembly language program will be used. The Intel FPGA Monitor Program package contains several sample programs. Select the box Include a sample program with the project. Then, choose the Getting Started program, as indicated in the figure, and click Next.
The window in Figure 5 is used to specify the source file(s) that contain the application program(s). Since we have selected the Getting Started program, the window indicates the source code file for this program. This window also allows the user to specify the starting point in the selected application program. The default symbol is _start, which is used in the selected sample program. Click Next.
The window in Figure 6 indicates some system parameters. Note that the figure indicates that the DE-SoC [USB-1] cable is selected to provide the connection between the DE-series board and the host computer. This is the name assigned to the Intel USB-Blaster connection between the computer and the board. Click Next.
3
Figure 4: Selection of an application program.
Figure 5: Source files used by the application program.
4
Figure 6: Specify the system parameters.
The window in Figure 7 displays the names of Assembly sections that will be used for the program, and allows the user to select a target memory location for each section. In this case only the .text section, which corresponds to the program code (and data), will be used. As shown in the figure, the .text section is targeted to the DDR3 memory in the DE-series board, starting at address 0. Click Save to complete the specification of the new project.
Since you specified a new project, a pop-up box will appear asking you if you want to download the system associated with this project onto the DE-series board. Make sure that the power to the board is turned on and click Yes. After the download is complete, a pop-up box will appear informing you that the circuit has been successfully downloaded—click OK. If the circuit is not successfully downloaded, make sure that the USB connection, through which the USB-Blaster communicates, is established and recognized by the host computer. (If there is a problem, a possible remedy may be to unplug the USB cable and then plug it back in.)
5
Figure 7: Specify the program memory settings.
Having downloaded the computer system into the Cyclone V SoC chip on your DE1-SoC board, we can now load and run the sample program. In the main Monitor Program window, shown in Figure 8, select Actions Compile & Load to assemble the program and load it into the memory on the board. Figure 8 shows the Monitor Program window after the sample program has been loaded.
Run the program by selecting Actions Continue or by clicking on the toolbar icon , and observe the patterns displayed on the LEDs.
Pause the execution of the sample program by clicking on the icon , and disconnect from this session by clicking on the icon ,
6
Figure 8: The monitor window showing the loaded sample program.
7
Part II
Now, we will explore some features of the Monitor Program by using a simple application program written in the ARM assembly language. Consider the program in Figure 9, which finds the largest number in a list of 32-bit integers that is stored in the memory.
/* Program that finds the largest number in a list of integers */
.text
// executable code follows
.global
_start
_start:
MOV
R4, #RESULT
// R4 points to result location
LDR
R2, [R4, #4]
// R2 holds number of elements in the list
MOV
R3, #NUMBERS
// R3 points to the list of integers
LDR
R0, [R3]
// R0 holds the largest number so far
LOOP:
SUBS
R2, #1
// decrement the loop counter
BEQ
DONE
// if result is equal to 0, branch
ADD
R3, #4
LDR
R1, [R3]
// get the next number
CMP
R0, R1
// check if larger number found
BGE
LOOP
MOV
R0, R1
// update the largest number
B
LOOP
DONE:
STR
R0, [R4]
// store largest number into result location
END:
B
END
RESULT:
.word
0
N:
.word
7
// number of entries in the list
NUMBERS: .word
4,5,3,6
// the data
.word
1,8,2
.end
Figure 9: Assembly-language program that finds the largest number.
Note that some sample data is included in this program. The word (4 bytes) at the label RESULT is reserved for storing the result, which will be the largest number found. The next word, N, specifies the number of entries in the list. The words that follow give the actual numbers in the list.
Make sure that you understand the program in Figure 9 and the meaning of each instruction in it. Note the extensive use of comments in the program. You should always include meaningful comments in programs that you will write!
Perform the following:
Create a new folder for this part of the exercise, with a name such as Part2. Create a file named part2.s and enter the code from Figure 9 into this file. Use the Monitor Program to create a new project in this folder; we have chosen the project name part2. When you reach the window in Figure 4 choose Assembly Program but do not select a sample program. Click Next.
Upon reaching the window in Figure 5, you have to specify the source code file for your program. Click Add and in the pop-up box that appears indicate the desired file name, part2.s. Click Next to get to the window in Figure 6. Again click Next to get to the window in Figure 7. Notice that the DDR3_SDRAM
8
is selected as the memory device. Your program will be loaded starting at address 0 in this memory. Click Finish.
Compile and load the program. Monitor Program will display a disassembled view of the machine code loaded in the memory, as indicated in Figure 10.
Execute the program. When the code is running, you will not be able to see any changes (such as the contents of registers or memory locations) in the Monitor Program window, because the Monitor Program cannot communicate with the ARM processor while code is being executed. But, if you pause the program then the Monitor Program window will be updated. Pause the program using the icon and observe that the processor stops within the endless loop END: B END. Note that the largest number found in the sample list is 8 as indicated by the contents of register R0. This result is also stored in memory at the label RESULT. The address of the label RESULT for this program is 0x00000038. Use the Monitor Program’s Memory tab, as illustrated in Figure 11, to verify that the resulting value 8 is stored in the correct location.
You can return control of the program to the start by clicking on the icon , or by selecting Actions Restart. Do this and then single-step through the program by clicking on the icon . Watch how the instructions change the data in the processor’s registers.
Double-click on the pc register in the Monitor Program and then set the program counter to 0. Note that this action has the same effect as clicking on the restart icon .
Now set a breakpoint at address 0x0000002C by clicking on the gray bar to the left of this address, as illustrated in Figure 12. Restart the program and run it again. Observe the contents of register R0 each time the instruction at the breakpoint, which is B LOOP, is reached.
Figure 10: The disassembled view of the program in Figure 9.
9
Figure 11: Displaying the result in the memory tab.
Figure 12: Setting a breakpoint.
10
Part III
Implement the task in Part II by modifying the program in Figure 9 so that it uses a subroutine. The subroutine, LARGE, has to find the largest number in a list. The main program passes the number of entries and the address of the start of the list as parameters to the subroutine via registers R0 and R1. The subroutine returns the value of the largest number to the calling program via register R0. A suitable main program is given in Figure 13.
Create a new folder and a new Monitor Program project to compile and download your program. Run your program to verify its correctness.
/* Program that finds the largest number in a list of integers */
.text
// executable code follows
.global
_start
_start:
MOV
R4, #RESULT
// R4
points to result location
LDR
R0, [R4, #4]
// R0
holds the number of elements in the list
MOV
R1, #NUMBERS
// R1
points to the start of the list
BL
LARGE
STR
R0, [R4]
// R0
holds the subroutine return value
END:
B
END
/* Subroutine to find the largest integer in a list
Parameters: R0 has the number of elements in the lisst
R1 has the address of the start of the list
Returns: R0 returns the largest item in the list
*/
LARGE:
. . .
. . .
RESULT:
.word
0
N:
.word
7
// number of entries in the list
NUMBERS:
.word
4,5,3,6
// the data
.word
1,8,2
.end
Figure 13: Main program for Part III.
Part IV
The program shown in Figure 14 converts a binary number into two decimal digits. The binary number is loaded from memory at the location N, and the two decimal digits that are extracted from N are stored into memory in two bytes starting at the location Digits. For the value N = 76 (0x4c) shown in the figure, the code sets Digits to 00000706.
Make sure that you understand how the code in Figure 14 works. Then, extend the code so that it converts the binary number to four decimal digits, supporting decimal values up to 9999. You should modify the DIVIDE subroutine so that it can use any divisor, rather than only a divisor of 10. Pass the divisor to the subroutine in register R1.
If you run your code with the value N = 9876 (0x2694), then Digits should be set to 09080706.
11
/* Program that converts a binary number to decimal */
.text
// executable code follows
.global
_start
_start:
MOV
R4, #N
MOV
R5, #Digits
// R5 points to the decimal digits storage location
LDR
R4, [R4]
// R4 holds N
MOV
R0, R4
// parameter for DIVIDE goes in R0
BL
DIVIDE
STRB
R1, [R5, #1]
// Tens digit is now in R1
STRB
R0, [R5]
// Ones digit is in R0
END:
B
END
/* Subroutine to perform the integer division R0 / 10.
* Returns: quotient in R1, and remainder in R0
*/
DIVIDE:
MOV
R2, #0
CONT:
CMP
R0, #10
BLT
DIV_END
SUB
R0, #10
ADD
R2, #1
B
CONT
DIV_END:
MOV
R1, R2
// quotient in R1 (remainder in R0)
MOV
PC, LR
.word 76// the decimal number to be converted
Digits: .space 4 // storage space for the decimal digits
.end
Figure 14: A program that converts a binary number into two decimal digits.
12