CSCI 320 — Introducing MPLAB® X & MIPS assembly

CSCI 255 preparation

We are making the assumption that you have taken CSCI 255 recently and have completed the lab CSCI 255 — Introducing MPLAB X & PIC assembly. If you haven’t, you may need to do a bit of out-of-lab work or come to lab both weeks.

You can download your own copy of MPLAB X from Microchip’s MPLAB  X download page. You will want a copy of the following:

In CSCI 255 we used the PIC24 processor, but in CSCI 320 we are using the MIPS-based PIC32. You can get a list of MIPS32 instructions from the MIPS32® Instruction Set Quick Reference.

Getting Started

From the command line you can type mplab_ide or you can use your mouse to run MPLAB IDE using the Linux menu selections ApplicationsProgrammingMPLAB IDE. (Don’t choose MPLAB IPE.) It may take a little while to start when you first fire up.

First MIPS32 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. From the Microchip Embedded category choose a Standalone Project.
  2. Choose the 32-bit MCUs (PIC32) family and then select the first device in the list. (Actually any device will do.)
  3. Select the Simulator as your hardware tool.
  4. Select XC32 as your compiler.
  5. Finally choose a project name, perhaps csci320mipsfun and click Set as main project.

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.

Notice that your project is stored in a directory with names that end with a capital X, such as csci320mipsfun.X .

Checking it out — skip if you took CSCI 255

At this point you have a NetBeans environment that will be familiar to the alumni of CSCI 181 and 202 and (now) 255. 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 some assembler program

Now we’ll use the menu to create a assembler program. Right click on Source Files then NewOther... .

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.

## $t0-$t9  temporary registers
## $s0-$s7  saved values
## $a0-$a3  function arguments
## $v0-$v1  return values
## $ra      return address
## $sp      stack pointer
## $fp      frame pointer

#include    <xc.h>
## Data is defined here
x:          .long       255

## Code is defined here
            .global     main
            .set        noreorder
            .ent        main
            addi    $sp, $sp, -4
            sw      $ra, 0($sp)

            lw      $t0, x
            add     $t1, $t0, $t0
            add     $t0, $t0, $t1
            sw      $t0, x
            j       forever

            lw      $ra, 0($sp)
            addi    $sp, $sp, 4
            jr      $ra

            .end    main

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

This program is roughly equivalent to this segment of Java code.

short x = 255 ;
while (true) {
   x = 3*x + 1 ;

What’s it all about

Like most assembly language programs, this one contains several pseudo-ops or directives. These are lines of code that don’t create instructions.

The program starts with the directive to include the xc.h, a file containing definitions of useful constants for programming PIC microcontrollers. We won’t be doing that in CSCI 320. Later you will see directives for defining the data and text (code) sections for your program. There is also a line where an integer variable x is defined and initialized to 255.

Executing a program

The Microchip simulator does know how to simulate the MIPS32 instructions of your program, but all the program does is loop forever. To see anything interesting you must step through the program.

To do this you need to know how to set breakpoints in your program. Now we are going to assume you learned how to set breakpoints in either CSCI 202 or 255. If you haven’t, you may need to review the CSCI 255 lab.

Set the breakpoint at the addi instruction right after the main label.

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. Take a look at the Variables, CPU Memory and Data Memory tabs. (If you don’t set them, add them.) You’ll find the MIPS32 registers in the CPU Memory tab.

Press the F8 key to step through your program. Switch between the Variables and CPU Memory tabs to see the current values of x, $t0, $t1. If x is being displayed as a 2-byte value, right-click on the variable name and set its size to 4 bytes. (I think this could be a bug.)

Step through your program until the variable x is more than 1000000.

Then keep going until the addition overflows and the simulator restarts your program at the beginning of main.

To end your debugging session, you can press the little x on the right lower edge of the screen or type SHIFT+F5.

Checking the status bits

Oops! There are no status bits in the MIPS32. I must have been thinking about the PIC24 in CSCI 255 for a minute.

Trying out arrays

Yes, it is the same example used in the CSCI 255 lab, but even longer.

Like is CSCI 255, it’s an abbreviated description. Create a MPLAB X project that contains this program.

## $t0-$t9  temporary registers
## $s0-$s7  saved values
## $a0-$a3  function arguments
## $v0-$v1  return values
## $ra      return address
## $sp      stack pointer
## $fp      frame pointer

#include    <xc.h>
            .equ       aSize,100
## Data is defined here
i:          .long      0
j:          .long      0
V:          .fill      aSize,4
x:          .long      0
y:          .long      0
z:          .long      0
vSize:      .long      aSize

## Code is defined here
            .global    main
            .set       noreorder
            .ent       main
            addi       $sp, $sp, -4
            sw         $ra, 0($sp)

## initialize V to the first 100 square numbers
            lw         $t0,vSize        ## 100, 99, 98, 97, 
            la         $t1,V            ## &V[0], &V[1], &V[2], 
            add        $t2,$0,$0        ## 0, 1, 4, 9, 16, ...
            addi       $t3,$0,1         ## 1, 3, 5, 7, 9, ...
            sw         $t2,0($t1)
            add        $t2,$t2,$t3
            addi       $t3,$t3,2
            addi       $t1,$t1,4
            addi       $t0,$t0,-1
            bne        $t0,$0,initloop

## Your answers should work for these 10 sections of code
## regardless of the initial values of i and j

## sect 0
## x = V[15] ;

## sect 1
## V[17] = -17 ;

## sect 2
## y = V[i] ;

## sect 3
## V[j] = -19 ;

## sect 4
## x = V[i+5] ;

## sect 5
## V[i+j] = -23 ;

## sect 6
## i = (i+j)/2 ;

## sect 7
## V[i] = V[j] ;

## sect 8
## V[16] = V[24] ;

## sect 9
## V[++i] = V[j+=5] ;

            lw      $ra, 0($sp)
            addi    $sp, $sp, 4
            jr      $ra

            .end    main

The loop at the beginning of the program initializes the array V to contain the first 100 squares.

What you are supposed to do

There are ten comments containing short sequences of C/Java code after the loop. See how many of these you can complete.

Remember that the elements of V are four bytes long. Consider using the SLL instruction for a two-bit shift.