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)