My dear reader, how are you? السلام عليكم
Education is what remains after one has forgotten what one has learned in school – Albert Einstein
In this post, I explain the assembly language programming in MIPS32 on a real-world RISC based microprocessor. This post also contains the working examples of simple assembly programs running on ci20, i.e., a Creator Dev embedded processor platform.
Introduction to ci20 board
Embedded system
An embedded processor is a type of microprocessor designed into a system to control electrical and mechanical functions. Embedded processors are usually simple in design, limited in computational power and I/O capabilities, and have minimal power requirements.
What is ci20?
A MIPS32 based embedded processor.
The MIPS Creator Ci20 is a high performance, fully-featured embedded development board for Linux and Android that can help you create applications for fast-growing markets such as IoT, wearables, mobile, and gaming. It incorporates an Ingenic JZ4780 SoC which includes a 1.2GHz dual-core MIPS32 processor and Imagination PowerVR SGX540 GPU.
Detailed specifications are given below:
-1.2GHz dual-core XBurst MIPS32 JZ4780 SoC with PowerVR SGX540 GPU and FPU
– GPU supports MPEG-4, H.264, VP8, MPEG-2, and RV9
– On-board 1GB DDR3 SDRAM
– On-board 8GB NAND Flash memory
– On-board IW8103 IEEE 802.11b/g/n WiFi and Bluetooth 4.0 wireless module
– On-board DM9000C Ethernet controller and PHY
– Infrared (IrDA) receiver for remote control
– Reset and Boot pushbuttons
-Jumper link for Boot mode (SD card or Flash)
– 4 x status LEDs
– USB activity LED
– HDMI socket for 1080p video
– SD card slot
– USB-A socket for USB 2.0 OTG
– USB-A socket for USB 2.0 Host
– USB mini-B socket for power supply
– RJ45 socket for 10/100 Ethernet LAN
– 24-pin ITU-645 camera connector
– 3.5mm stereo audio output and microphone input jack socket
– 26-pin Primary Expansion header for GPIO/SPI/I²C, Raspberry Pi compatible
– 16-pin Secondary Expansion header for ADC, touch sensing and battery monitor
– 4-pin UART header
-14-pin MIPS EJTAG header
– Power supply: +5Vdc @ 1A via 1.7mm barrel jack socket or USB mini-B socket
– Dimensions: 100 x 92mm
Overview of ci20
How to power on Ci20?
Just plug it in.
Yes! Out of the box, the CI20 is ‘ready to go’. By default, it will boot the OS image (Debian7).
How to use Ci20?
There are two options:
- To really use the board, it will need at minimum an HDMI screen, a USB keyboard, and a mouse.
- Ci20 can also be configured to provide headless support. A headless system is a computer that operates without a monitor, graphical user interface (GUI) or peripheral devices, such as keyboard and mouse.
How to use ci20 as a headless processor?
The open-ssh server is already installed on Ci20. Using your laptop or PC (i.e., client), you can ssh in the board provided the IP is known.
How to log-in as root?
Type the following command in the terminal
$ su root
(when prompted for the password, enter ‘ci20’)
Assembly programming on ci20
First example program
- Login to ci20 as root.
- Create a new file “firstprogram.s”.
$ vim.tiny firstprogram.s
# press “i” to insert text in the file .text .global __start __start: li $a0, 50 li $v0, 4001 syscall
- Save and quit the file.
(press Esc and then :wq to write changes in the file and exit)
- Assemble and Link.
$ as firstprogram.s -o firstprogram.o # AS is a GNU assembler. Details: DirectMe $ ld firstprogram.o -o firstprogramexe # And run it. $ ./firstprogramexe
- Check the answer.
$ echo $? # The computer will output 50.
Explanation
- .text identifies the text region. The processor will start computing here.
- .global __start defines a position in the program that you want to refer to as “__start”.
- __start is the label for the ease of programmer to name the start address at a specific place.
- li $a0, 50 means load immediate and places the value 50 into register a0.
- li $v0, 4001 means “load immediate” and places the value 4001 into register v0.
- syscall calls the operating system for help. Syscall() is a small library function that invokes the system call whose assembly language interface has the specified number with the specified arguments.
Use registers with numbers
$ vim.tiny secondprogram.s
.text .global __start __start: li $4, 50 li $2, 4001 syscall
Compile and run the program using the aforementioned steps.
Linux syscalls for 32-bit OS
For a complete list of available Linux syscalls for MIPS32 check the link DirectMe.
hello world program on ci20
- Create a file and save it as “helloworld.s”
.data string: .asciiz "Hello World!\n" .text .global __start __start: li $a0, 0 la $a1, string li $a2, 13 li $v0, 4004 syscall li $a0, 3 li $v0, 4001 syscall
- Compile and run the program
$ as helloworld.s -o helloworld.o $ ld helloworld.o -o helloworld $ ./ helloworld # prints "Hello World!" $ echo $? # prints "3"
Use words for calling syscall instead of numbers
- Using vim.tiny create a file “wordsyscall.S” and enter the following code into it. Note the capital S.
#include <regdef.h> #include <sys/syscall.h> .data string: .asciiz "Hello World!\n" length: .word 13 .text .global __start __start: li a0, 1 la a1, string lw a2, length li v0, SYS_write syscall li a0, 6 li v0, SYS_exit syscall
- Note that we have included C libraries in our assembly program. So now first we need to do preprocessing using GCC (C language compiler) as shown below.
$ gcc -S wordssyscall.S > wordssyscall.s # note the capital S and small s
Check the output of preprocessing
$ more wordssyscall.s
- Now assemble, link and run the program as shown below
$ as wordssyscall.s -o wordssyscall.o $ ld wordssyscall.o -o wordssyscallexe $ ./wordssyscallexe
How to do a loop?
- Using vim.tiny create a file “helloworldloop.S” and enter the following code into it. Note the capital S.
#include <sys/regdef.h> #include <sys/syscall.h> .data .align 2 hello: .asciiz "Hello World!\n" .align 4 length: .word 13 .text .global __start __start: move s1, $0 addi s1, s1, 9 __loop: move a0, $0 la a1, hello lw a2, length li v0, SYS_write syscall addi s1, -1 bne s1,0, __loop li a0, 6 li v0, SYS_exit syscall
- Preprocessing, assembling, linking and execution will go as below
$ gcc -S helloworldloop.S > helloworldloop.s # Note the capital S and small s # Check the output of preprocessing $ more helloworldloop.s $ as helloworldloop.s -o helloworldloop.o $ ld helloworldloop.o -o helloworldloopexe $ ./helloworldloopexe
I hope you find this post useful. If you find any errors or feel any need for improvement, let me know in your comments below.
Signing off for today. Stay tuned and I will see you next week! Happy learning.