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.

Image result for ci20

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

Image result for ci20 components

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


        .global __start


        li      $a0,    50
        li      $v0,    4001
  • 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.


  • .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

        .global __start


        li      $4,    50
        li      $2,    4001

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”

string:       .asciiz "Hello World!\n"


        .global __start


        li      $a0,    0
        la      $a1,    string
        li      $a2,    13
        li      $v0,    4004

        li      $a0,    3
        li      $v0,    4001
  • 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>


string:       .asciiz "Hello World!\n"
length:         .word   13


        .global __start


        li      a0, 1
        la     a1, string
        lw    a2, length
        li      v0, SYS_write

        li      a0, 6
        li      v0, SYS_exit
  • 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>

        .align  2
        hello:  .asciiz  "Hello World!\n"
        .align          4
        length:         .word 13


        .global __start


        move    s1, $0
        addi    s1, s1, 9


        move    a0, $0
        la      a1, hello
        lw      a2, length
        li      v0, SYS_write

        addi    s1, -1
        bne     s1,0, __loop

        li      a0, 6
        li      v0, SYS_exit
  • 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.


Please enter your comment!
Please enter your name here