Skip to content
Contents

Three shapes for every instruction: R, I and J

Section 1.3 12 min read

  • opcode
  • function code (funct)
  • R-format
  • I-format
  • J-format

Checked against: MIPS32 Vol. I §2 (instruction formats) carolyne_ref/isa_mips/field_match.py carolyne_ref/isa_mips/mop.py carolyne_ref/dumps/hello_o0.dump (bfc0008c: jal main)

Before you start

  • §1.1: one word is 32 bits, written as eight hex digits
  • §1.2: the nine instructions of the smoke program

By the end, you can

  • Name the three formats and the fields of each, with their bit positions
  • Cut a real word into its fields by hand and read the instruction
  • Explain why register fields are 5 bits and why nop is all zeros
  • Say how R-format instructions are told apart when the opcode is 0

Three shapes

Every MIPS instruction is one of three formats. The always sits in bits 31 to 26. What follows depends on the format.

formatfields, from bit 31 down to bit 0used for
Ropcode (6) · rs (5) · rt (5) · rd (5) · sa (5) · funct (6)register-to-register work: add, sll, mult, jr
Iopcode (6) · rs (5) · rt (5) · imm16 (16)anything with a constant: addiu, lw, sw, beq, lui
Jopcode (6) · index (26)j and jal: jump far

Their names are , and . Every instruction uses exactly one of them.

Here are three real words from the programs you have seen. Hover any field.

R-format: mult $t2,$t3 from the smoke program (0x014B0018)

Opcode 0 means 'look at funct'. Which field says mult?

3126
opcode6b
000000
0 = SPECIAL
2521
rs5b
01010
$t2 ($10)
2016
rt5b
01011
$t3 ($11)
1511
rd5b
00000
0
106
sa5b
00000
0
50
funct6b
011000
24 = mult
binary00000001010010110000000000011000
hex0x014b0018one hex digit = four bits; a digit that spans two fields has two colors
asmmult $t2,$t3R-format
Hover or focus a field to see its bits, value and role.

What to notice

The opcode is 0. That does not mean “no operation”. It means “this is an R-type: the answer is in funct”. Here funct = 24, which is mult. The rd and sa fields are unused, so they are zero.

I-format: addiu $t1,$zero,72 from the smoke program (0x24090048)

Where is the 72, and how wide is it?

3126
opcode6b
001001
9
2521
rs5b
00000
$zero ($0)
2016
rt5b
01001
$t1 ($9)
150
imm16b
0000000001001000
72 (0x0048)
binary00100100000010010000000001001000
hex0x24090048one hex digit = four bits; a digit that spans two fields has two colors
asmaddiu $t1,$zero,72(objdump prints li $t1,72)I-format
Hover or focus a field to see its bits, value and role.

What to notice

The opcode alone says addiu. rs is $zero, rt is $t1, and the bottom 16 bits hold 72. There is no rd: an I-format instruction writes rt.

J-format: jal main from hello.c at -O0 (0x0FF00063 at 0xBFC0008C)

How does a 26-bit field name a 32-bit address?

3126
opcode6b
000011
3
250
index26b
11111100000000000001100011
66060387 (× 4 = 0x0fc0018c)
binary00001111111100000000000001100011
hex0x0ff00063one hex digit = four bits; a digit that spans two fields has two colors
asmjal 0xbfc0018cJ-format
Hover or focus a field to see its bits, value and role.

What to notice

Everything under the opcode is one 26-bit number. Multiply it by 4, keep the top four bits of the PC (program counter), and you get 0xBFC0018C, the address of main. Chapter 5 explains why that reaches most of memory.

Why the fields are these sizes

  • Register fields are 5 bits because 2⁵ = 32. That is why MIPS has exactly 32 registers. One more register would need a sixth bit in three places.
  • The opcode is 6 bits, so there are 64 possible opcodes. Three of them (0, 28, 31) say “look at funct”, which gives 64 more each. That is how 63 instructions fit with room to spare.
  • The constant (the immediate) is what remains. After opcode, rs and rt, 16 bits are left. That is why §1.2 needed two instructions to build a 32-bit address.
  • A jump index is 26 bits because j needs no register. The whole word below the opcode is the target.

is the field to remember. For R-types, the opcode is a table name and funct is the row.

Decode one by hand

Take 0x014B0018 and write the eight hex digits as bits. Then cut.

bitsfieldbinaryvaluemeaning
31–26opcode0000000SPECIAL: an R-type, read funct
25–21rs0101010$t2
20–16rt0101111$t3
15–11rd000000unused
10–6sa000000unused
5–0funct01100024mult

So the word is mult $t2,$t3. You can now read any word in a dump the same way. In practice you let the tool do it, but once by hand is worth it.

Cut this one yourself first:

`sw $t1,0($t0)` is the word 0xAD090000. Which field holds $t1, the data being stored?

Try it: change a field, watch the bits

Pick a different register or a different constant. The bits that change light up. Switch the instruction to sll to see the sa field come alive.

Build a word yourself

Which bits move when you change rd? Which move when you change the instruction?

3126
opcode6b
000000
0 = SPECIAL
2521
rs5b
01000
$t0 ($8)
2016
rt5b
01001
$t1 ($9)
1511
rd5b
01010
$t2 ($10)
106
sa5b
00000
0
50
funct6b
100000
32 = add
binary00000001000010010101000000100000
hex0x01095020one hex digit = four bits; a digit that spans two fields has two colors
asmadd $t2,$t0,$t1R-format
Hover or focus a field to see its bits, value and role.
change a field and watch which bits move

What to notice

Changing a register moves exactly five bits. Changing add to addu moves one bit, in funct. Changing add to addiu changes the shape: the rd, sa and funct boxes disappear and a 16-bit constant appears.

nop is all zeros

The nop you saw after every branch is the word 0x00000000. MIPS has no separate “do nothing” instruction. Opcode 0 and funct 0 is sll, so the word means sll $zero,$zero,0: shift $zero by zero and write $zero. It is a real instruction that changes nothing. The assembler prints the alias nop.

The instructions you have met so far

Ten instructions is a good start. Here they are, with their formats and codes. Click a row to see its encoding. The full table of 63 comes in §9.4.

The instructions of chapter 1

Which are R, which are I, and which one is J?

10 of 10
instructionformatcodeoperandsmeaningunittaught in

What to notice

Six of the ten are I-format: they all carry a constant. mult, mflo and sll are R-format, with opcode 0 and a funct. Only jal is J-format. Every row’s code column shows the field that names it.

Go deeper: how 63 instructions share 64 opcodes: the four escape tables

The six-bit opcode gives 64 values. MIPS uses four of them as doors to a second table:

  • 0 = SPECIAL: the classic R-types, chosen by funct (add, sub, and, or, sll, jr, mult, mfhi, …).
  • 1 = REGIMM: branches that compare one register with zero. The rt field is the sub-opcode: 0 = bltz, 1 = bgez, 16 = bltzal, 17 = bgezal.
  • 28 = SPECIAL2: mul, clz, clo (and the madd family, which this book does not use).
  • 31 = SPECIAL3: ext, ins, seb, seh. seb and seh share funct 32 and differ in sa (16 versus 24).

The other 59 opcodes name one instruction each: the loads, the stores, the immediates, j, jal, beq, bne, blez, bgtz, lui. Carolyne’s mop.py is exactly this list: one matcher per opcode group, and a second matcher on funct, rt, rs or sa where a group needs it.

Can you now explain it?

A MIPS word is opcode plus fields. R-format names three registers and a funct. I-format names two registers and a 16-bit constant. J-format is one 26-bit target.

If you remember only three things

  1. The opcode is the top six bits, always. It is a table name. For opcodes 0, 28 and 31 the row is chosen by funct; for opcode 1 by rt; otherwise the opcode is the instruction.
  2. Five bits name a register; sixteen hold a constant. That is why there are 32 registers and why a 32-bit address takes two instructions.
  3. Assembly order is not bit order. add rd,rs,rt writes rd, which sits in bits 15–11, after rs and rt. The syntax string of each instruction says which field each operand fills.

Now try to explain this one yourself: the word 0x00000000 is nop, and 0x00000020 is add $zero,$zero,$zero. Both change nothing. Why did MIPS choose the shift, not the add, as the official nop?

Go deeper: a model answer, once you have tried

Both words write $zero, which throws the result away, so both are harmless. The all-zero word is the natural choice for two reasons. First, memory that has been cleared to zero then reads as a stream of harmless instructions, which is safer than reading as something else. Second, add can trap on overflow (§3.1); sll can never trap, so it is safe in every state. funct 0 was given to sll for exactly this reason.

Check your understanding

0/5 answered
  1. 1.The word 0x3C081000 is `lui $t0,0x1000`. Which format is it?

  2. 2.`jal main` is the word 0x0FF00063. Why does the word not simply hold main's full 32-bit address?

  3. 3.Why is `nop` the all-zero word 0x00000000?

  4. 4.Register fields are 5 bits wide. How many registers can such a field name?

  5. 5.Where is the opcode in a MIPS word, and where is it in a RISC-V word?


Next: Chapter 2 — the 32 registers, HI, LO and the PC.

Where this comes back

11 later sections build on this one.