MIPS: Machine without Interlocking Pipeline Stages

CS 441 Lecture, Dr. Lawlor

So in 1981 a smart computer science professor, John Hennessy, realized that a new CPU that used pipelining could be made to run very fast.  He put together a new, simpler instruction set called MIPS.  In 1984 he left academia to form a company to produce his new CPUs.

Through the 1980's, the MIPS architecture flourished, and was used in several high-end systems, such as those from Silicon Graphics, Inc (SGI).  The NetRun MIPS machine is actually an old SGI.  MIPS was one of the first widely-licensed designs, where many companies bought the VHDL code for a MIPS CPU, added their own special interfacing hardware, and built their own chips.

MIPS still sees some use in embedded CPUs, such as cell phones, routers, and set-top boxes, but x86-compatible or PowerPC CPUs have almost entirely displaced MIPS from the desktop, server, and high-performance computing markets.

Nonetheless, the MIPS instruction set is a good way to learn about instruction set design and the hardware/software tradeoff.

MIPS Information Sources

MIPS Example Code

Here's the classic example of MIPS weirdness.  Jumps (such as Jump to Register $31, the return address register) actually take effect one instruction after they're issued, so you have one free "branch delay" slot you can fill with any one-cycle instruction:
jr $31        # return from function...
li $2,42 # ...but first, load up the return value!
(executable NetRun link)

MIPS, like all RISC machines, does arithmetic between registers:
li $4, 10
li $5, 3
add $2, $4, $5
(executable NetRun link)

This is how you make a kernel system call, in this case to directly print a string.
li $2,1004    # System call number of write
li $4,1 # File descriptor to write to
add $5,$25,28 # Points to the string below (hopefully!)
li $6,7 # Bytes to write out

syscall # issue the syscall

jr $31 # return from function
nop

.ascii "Hello!\n"
nop
(executable NetRun link)

This example shows the nasty function prologue and epilogue needed to call C library functions, which live in a dynamic library, and hence require the strange ".cpxxx" PIC support directives:
# Function prologue
.option pic2 # Write Position-Independent-Code (PIC), that can call shared libraries
.cpload $25 # Load up the $gp register from $25 (which contains our address)
subu $sp, 40 # Make room on the stack
sw $31, 36($sp) # Save our link register into our stack frame
.cprestore 32 # Store $gp register into our stack frame (used in jal)

# Function body
la $4, my_string # Load Address of string to print out
jal printf # Call printf function

li $2,42 # Return value

# Function epilogue
lw $31, 36($sp) # Restore link register from stack frame
addu $sp, 40 # Clean up stack
jr $31 # Return from function
nop # branch-delay slot

.data # Stuff from here on is data, not code
my_string:
.asciiz "Sup?\n"
(executable NetRun link)