CSCI 255 — Introduction to MIPS32 Assembly

In this lab we are going to use MPLAB® X IDE and its associated XC32 compiler to write and debug an assembler program for the PIC32, a microcontroller based on the MIPS32 architecture. The MPLAB X software is NetBeans based and will run under Linux, Mac and Windows.

You can download your own copy of MPLAB X from Microchip’s MPLAB  X download page. You will need to install the following:

You can get a short list of instructions from the MIPS “Green Card”. Section 2 of the PIC32 Family Reference Manual, CPU for Devices with M4K core. If you want 330 pages about MPLAB X, check out the MPLAB® X IDE User’s Guide. The definitive guide to the XC32 assembler is the 234 page MPLAB® XC32 Assembler, Linker and Utilities User’s Guide. Information relevant to the assembler is also contained in the MPLAB® XC32 C/C++ User’s Guide.

Getting Started

From the command line you can type mplab_ide or you can type “mplab” in the search box at the top of the launcher. Be sure to select MPLAB IDE and not MPLAB IPE. (IPE is Integrated Programming Environment. In embedded system design, “programming” is the process of downloading code to the chip.)

If you’ve used NetBeans, you’ll feel at home with. MPLAB X.

First Project in MPLAB X

Creating the project

Use the menu choices FileNew Project... to begin the process of creating a project. Then work your way through a few windows.

  1. In the Choose Panel window, from the Microchip Embedded category choose a Standalone Project.
  2. In the Select Device window, select any device from the 32-bit MCUs (PIC32) family. I chose PIC32MX250F256H. Next time you’ll be able to speed up this process by choosing the Recently Used family.
  3. In the Select Tool window, go for the Simulator.
  4. In the Select Compiler window, select a XC 32. There should be only one choice.
  5. In the Select Project Name and Folder window, think of a clever project name and and click Set as main project.

You can click on the following images, if you think they are too small.

Choose Project Select Device Select Tool Select Compiler Select Name and Folder

You may have noticed that many of selected choices were preceded by a little green dot. Avoid the ones with the red and yellow dots.

Let’s mention a couple of things before going on.

There were a lot of devices to choose from. If you are using the simulator, as we are today, you don’t have to be that precise in your selection, but usually you must choose the device the that matches the one you plan is use in your project.

The XC 32 is Microchip’s latest compiler for its 32-bit processors. We are using the free (unlicensed) version. The free compiler is based on the gcc toolchain and it does not optimize your C code. It will cost you about $1000 to get the optimizing “PRO” compiler.

Also, notice that your projects are going to be stored in directories with names that end with a capital X, such as CSCI255rocks.X .

Right-click on the name of your project and then select Properties. Make sure you have chosen well.

Checking it out the IDE

At this point you have a NetBeans environment that will be familiar to alumni of CSCI 181 and 202. Move your mouse over the menu choices at the top of the window, from File to Help. Press on the choices to look at their submenus. Pay particular attention to items under Debug. Most of the choices are presently grayed out, because they can’t be used until you are working on a project.

Notice that the lower left corner is occupied by a Dashboard display. The Microchip PIC devices have very little memory so we need an easy-to-use means of figuring out how much memory our programs are using.

Adding an assembler program

Now we’ll use the menu to create an assembler program. Start with the menu choices FileNew File...

Choose File Type Name and Location

At this point, you should have an empty program in the upper-right window. Make sure that your program really is under Source Files.

Copy the following program into your empty window. Take care that your program ends with a CRLF.

#include <xc.h>
         .global    main

         .data
a:      .int       2
b:      .int       8
c:      .int       17
x:      .int       10
z:      .int       -1

        .text
        .set       noreorder
        .ent       main
main:
##      z = a*x*x + b*x + c
##      $t0 = a
        lw         $t0,a
##      $t1 = b
##      $t2 = c
##      $t3 = x
##      $t4 = a*x
        mul        $t4,$t0,$t3
##      $t4 = $t4*x
##      $t5 = b*x
##      $t4 = $t4+$t5
        add        $t4,$t4,$t5
##      $t4 = $t4+c
##      z = $t4
spin:   j          spin
        nop

       .end        main

Go ahead and press the hammer to built it so we can make sure your installation is working.

This program is the start of an assembly language implementation of the following statement which can be in Java, C++, C, Python, JavaScript, ....

    z = a*x*x + b*x + c

What’s it all about

But clearly this isn’t Java, C++, C, Python, or even JavaScript.

Let’s look at this program for a minute. Like most assembly language programs, this one contains several pseudo-ops or directives. These are lines of code that don’t create instructions. They may define space for variables or control the assembly process or even control the spacing for a printout of your code.

System files

The program starts with the directive:
    #include <xc.h>
which would a legal statement in either C++ or C. This causes the assembler to include a file defining useful constants for programming PIC microcontrollers. Open the file /opt/microchip/xc32/v1.40/pic32mx/include/xc.h in MPLAB X using FileOpen File... (That took a little time, didn t it.)

That one isn’t that interesting. It’s just a list of include files for several different PIC processors. Try again, but this time open /opt/microchip/xc32/v1.40/pic32mx/include/proc/p32mx250f256h.h in MPLAB X. Using EditFind... or simply Ctrl+F find the definition of PORTB, the special function register you used in the Arduino lab. The volatile keyword is common to Java and C and denotes a variable that can be changed by external forces. __attribute__ is an extension of GNU CC that is rarely encountered in user programs. The __attribute__((section("sfrs"))) indicates that PORTB is a special function register.

We are serious. You need to know how to navigate the file system from the IDE. Show us the line defining PORTB.

Segments

Now close those two big system .h files and get back to your program.

The second line in your program is also a directive:
         .global    main
This causes the assembler to announce main as an external variable of your program. This means that the outside “world” will know about main. This is a bit like declaring a method public in Java.

Since ancient times, running programs have been considered to consist of four segments: (1) the text segment, which contains compiled code; (2) the stack segment, which contains local variables used by functions or methods; (3) the heap segment, which contains dynamically allocated memory, such as Java objects; and (4) the data segment, which contains global variables. The data area also contains the oddly name bss (block started by symbol) segment which contains space for uninitialized data. In this program, you see that both a text and data segment are defined. The data segment reserves room for the five variables a, b, c and z. The text segment contains the PIC instructions.

Executing a program

The Microchip simulator does know how to simulate the PIC instructions of your program, but right now your program does little more than loop forever. To see anything interesting you must step through the program.

Getting ready to run

To do this you need to know how to set breakpoints in your program. Move your mouse onto the narrow column of program line numbers just to the left of the first real instruction, the lw, of your program and click. There should put a little red square in the line number column and highlight the entire line in red to show that you have set a breakpoint.

Now use the menu choices DebugDebug Main Project. This should start the simulation but stop at the breakpoint.
Stopped at breakpoint

Put the break in your program and run your program to the breakpoint. If you have done this before using NetBeans, help out any lab neighbors who haven’t.

You will notice a bunch of new tabs in the lower right panel. One of them is called Variables. Go over to the Variables tab and add a watch for all your variables.
Variables tab
This is a little non-intuitive. You need to clink on <Enter new watch> and then enter the variable name.

However, all the action if with the registers. Use the window menu choices WindowPIC Memory ViewsCPU Registers to bring up a new tab called CPU Memory. Use the arrow keys to find registers $t0 to $t5 in this display. These registers are also known as $r08 to $r12.
Registers tab

By checking within the Hex or columns of the CPU Registers, you can change the values of registers.

Set the values of registers $t0 to $t5.

Now use WindowPIC Memory ViewsExecution Memory to see your assembly code translated into machine code in the Opcode column. The lw assembly language statement has been translated into a two-instruction machine language sequence. We will explain that in class.

Completing the program

Right now only three of the ten simple assignment statements have been completed. Complete the remaining seven and build your program.

You will need to use the sw instruction for the last assignment.

Debugging with the simulator

It’s time to run some code. Use the F8 key to step through your program while looking at the CPU Registers to see changes in the registers.

Step through the program one instruction at a time. After each instruction, verify that the expected result has been stored in the destination register.

In case of trouble

In the last few years, you wouldn’t get the expected results due to the way the mul instruction was handled in the simulator. That no longer seems to be the case. It appears the old simulator was broken.

However if there is a problem, go back to the end of the old lab and work on the part about delay slots.

In case time remains

If time permits, add four new variables n, o, p and e to your program and implement the following two C statements with code placed right before the spin label:

  n = (c & 0xFFF) <<  2 ;
  o = 3 * x + 1 ;
  p = a < b ;
  e = ~c ;

Use immediate instructions to implement the statements. Use the PIC32 reference table to find the instructions needed for your program. It’s mostly a matter of matched the C operator with the appropriate MIPS32 instruction.

In case of trouble....

If your windows get completely messed up, try some of the following: