These are details of the MIPS R2000 architecture.
The purpose of this is to give the flavor of how all architectures
have been designed/specified since the early 1980s. It is
different from Pentium.
Memory accesses slow a processor down. Sure, we add caches,
but that only brings the average access time down for memory
accesses. There are still times when the processor is doing
nothing, while waiting for memory accesses to complete.
So, we define a new architecture. In this new load/store
architecture, the addressing mode for every operand is fixed.
(So, there are no bytes for addressing mode information.)
And, for arithmetic/logical type instructions, the addressing
mode for all operands will be register mode. We make sure
that there are enough registers, because everything ends up
in registers. To get stuff to/from memory and into/out of registers,
we have explicit instructions that move data.
Load instructions read data from memory and copy it to a register.
Store instructions write data from a register to memory.
The MIPS R2000 is a load/store architecture.
There are 32 32-bit registers (for non-floating point operands).
(Integers are 32-bit two's complement; addresses are 32-bit unsigned.)
In code, the syntax used is $x, where x is a value
in the range of 0 to 31.
Example: $5 is register 5.
Some are special purpose:
$0 always contains the value 0. This has the effect of
reducing the number of instructions required in the
$1 used by the assembler
$2-3 location for function return values
$4-7 location for parameters
$26-27 used exclusively by OS
$31 return address from procedures placed here
There are also 16 64-bit registers used for floating point operands.
In code, the syntax used is $fx, where x is an even value
in the range of 0 to 30.
Example: $f6 is register 6.
Some of the floating point registers also have specific uses.
three-address instruction set
The instruction set is considerably smaller than the Intel
instruction sets. This is typical of a RISC processor.
There is generally one way to do a required operation, not
2 or 3 as on the Pentium.
Arithmetic and logical instructions have 3 operands.
Example: add $8, $9, $10
The contents of registers $9 and $10 are added,
and the result is placed in register $8.
To do the equivalent of this on the Pentium, you
would end up with something more like:
mov eax, var1
add eax, var2 ; eax <- var1 + var2
or, if one addend was in ebx, and the other was in ecx,
then the code could be
mov eax, ebx
add eax, ecx
Note that it can take fewer instructions to get the same
calculations done in the 3-address instruction set.
Thought question: What reason could there be for the Pentium
(and earlier Intel processors) to have a 2-address
instruction set, when the 3-address one is more
load and store instructions
The only instructions that access memory to get operands are
load and store instructions.
Examples: lw $14, 4($15)
Effective address given by base displacement addressing
mode (second operand). 4 + contents of register $15
are the address. Memory reference is to 1 word (32 bits)
at that address. The word read is placed into register
sb $10, 0($18)
Effective address given by base displacement addressing
mode (second operand). 0 + contents of register $18
are the address. The byte in the least significant
byte of register $10 is written to that address.
Notes: The first operand is always register mode.
The second operand is always base displacement mode.
There are 2 types of control instructions.
branch -- (equivalent of Pentium jumps)
conditional or unconditional
Branch decision (to take the branch or not) is based
on a comparison between the values in 2 registers.
(NOT condition codes!)
An offset from the instruction following the branch
is placed into the instruction.
jump -- unconditional
A portion of an absolute address is placed into the
Examples: beq $5, $13, label1
Branch if EQual. If the contents of registers $5
and $13 are the same (equal), then go to label1.
Jump And Link. A procedure call instruction very
much like the Pentium call instruction. The return
address is placed into register $31. (Pentium
pushes the return address onto the stack.) Then
address proc4 is placed into the PC.
All machine code instructions are exactly 32 bits long.
There are just a few basic formats:
arithmetic and logical instructions
bits 31 26 25 21 20 16 15 11 10 0
6-bit 5-bit 5-bit 5-bit
opcode reg reg reg more opcode
desig. desig. desig.
Since there is no addressing mode information (all operands
are register mode), an operand specification just takes 5
bits to tell which register is used.
Examples: add $8, $10, $12
sub $12, $8, $15
or $10, $11, $12
load/store, arithmetic/logicals that have one operand as an immediate
value, and all branch instructions
31 26 25 21 20 16 15 0
6-bit 5-bit 5-bit 16-bit immediate
opcode reg reg
Note that the location of the opcode and the locations of
the register designations are in the same location within
this 32-bit instruction. That makes decoding the instruction
easier (meaning faster, with less circuitry).
Examples: lw $20, 12($16)
addi $12, $8, -6
bne $13, $14, somewhere
Here is a code fragment of MIPS R2000 code.
# a MIPS code fragment to increment each element of
# an array of 100 integers.
addi $8, $0, 0 # value 0 goes into $8 (a counter)
addi $9, $0, 100 # $9 is ending value of counter
la $11, array # $11 is pointer into array of integers
beq $8, $9, done_loop
lw $10, 0($11) # get array element
addi $10, $10, 1 # add one to it
sw $10, 0($11) # put it back
addi $11, $11, 4 # update pointer
addi $8, $8, 1 # update counter
beq $0, $0, loop_top # uncondional branch
la is not really a MIPS R2000 instruction. It is an example of
and instruction that is allowed in assembly language code, but
is translated into MIPS R2000 code by the assembler. This makes
the job of writing this assembly language code easier.
For this la instruction, the assembler produces
(if symbol array is assigned address 0x00aa0bb0)
lui $11, 0x00aa # $11 gets value 0x 00aa 0000
ori $11, $11, 0x0bb0 # $11 gets value 0x 00aa 0bb0
The MIPS architecture does this with LOTS of instructions.