Skip to content
Contents

Jumping far: j, jal, jr, jalr

Section 5.3 9 min read

  • jump: no test, a 26-bit index
  • the 256 MB jump region
  • link: jal writes $ra = PC + 8
  • jr and jalr: jumping through a register

Checked against: MIPS32 Vol. II: J, JAL, JR, JALR carolyne_ref/dumps/hello_o0.dump (bfc0008c jal main; bfc00208 jr ra) carolyne_ref/isa_mips/imm.py (imm_j) carolyne_ref/isa_mips/exec_unit_br.py

Before you start

  • §1.3: J-format; §2.2: $ra
  • §5.1: branches are relative; the delay slot runs

By the end, you can

  • Compute a j or jal target from the index and the PC
  • Say what jal writes into $ra and why it is +8
  • Explain how jr $ra returns, and why it needs no hardware stack
  • Choose between jal, bal, and jalr for a call

Four jumps

A has no test. It always goes.

instructiongoes toalsoused for
j targetthe 26-bit index, in this region—far unconditional jumps
jal targetthe same$ra = its address + 8calling a function
jr rsthe address in rs—returning (jr $ra), switch tables
jalr rd,rsthe address in rsrd = its address + 8 (rd defaults to $ra)calling through a pointer

Like every branch, each jump runs the instruction after it before moving the PC (§5.4).

Where a jal goes: the index and the region

Here is the jal main that crt0 executes, from the dump:

jal main from crt0 (0x0FF00063 at 0xBFC0008C)

How can 26 bits 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.

From the index 0x3F00063 to the target 0xBFC0018C

Where do the top four bits come from?

0x0ff00063 at 0xbfc0008c: jal 0xbfc0018c

  1. 1. the 26-bit index field, bits 25–0 of the word0x03f00063
    00000011111100000000000001100011

    jal 0xbfc0018c: everything below the opcode is one number, 0x3f00063.

  2. 2. multiply by 4 (shift left by 2): 28 bits0x0fc0018c
  3. 3. the top 4 bits of PC + 40xb0000000
  4. 4. target = region | index × 40xbfc0018c
cycle 0/31 tick = 1 arithmetic step
  • the field, and bits an extension or shift filled
  • the branch/jump target

What to notice

The index is multiplied by 4, which gives 28 bits. The missing top four bits are copied from PC + 4, the delay slot’s address: 0xB. So the target is 0xBFC0018C, the address of main. Nothing is added to the PC; the index replaces the low 28 bits.

That means a jump can only reach its own : the 256 MB that share those top four bits. Your whole program sits inside 0xB0000000–0xBFFFFFFF, so every jal in it can reach every function.

jal does one more thing: it saves the way back. That is the . The saved address is the jal’s own address plus 8: not the next word, but the one after it. The next word is the delay slot, and it runs on the way out, so the return must land past it.

Watch two calls to one small function. The runner pauses before the first jal to ask you what $ra will become.

Two calls to one small function: jal links, jr $ra returns

How does a program call a function and get back to the right place afterwards?

program (address · word · instruction)

PC →0xbfc000000x3c191000_start:lui $t9,0x1000
0xbfc000040x37390ff0ori $t9,$t9,0xff0
0xbfc000080x24040041li $a0,65
0xbfc0000c0x0ff00009jal 0xbfc00024
0xbfc000100x00000000nop
0xbfc000140x24040042li $a0,66
0xbfc000180x0ff00009jal 0xbfc00024
0xbfc0001c0x00000000nop
0xbfc000200xaf200008sw $zero,8($t9)
0xbfc000240xaf240000put:sw $a0,0($t9)
0xbfc000280x03e00008jr $ra
0xbfc0002c0x00000000nop

registers — read · written this tick

HI 0x00000000LO 0x00000000PC 0xbfc00000

console (what the doors printed)

▮
cycle 0/151 tick = 1 instruction (not a cycle)

tick 0 of 15

Nothing has run yet. The PC (program counter) points at the first instruction.

At each jal, $ra turns green with the address of the instruction AFTER the nop under the jal. The function's jr $ra then sends the PC exactly there. The two calls come back to two different places, because $ra was different each time.

What to notice

At each jal, $ra turns green with the address after the nop. The function prints and ends with jr $ra, which sends the PC back there. The two calls return to two different places, because $ra was different each time. Nothing else remembers where the call came from.

Returning: jr $ra

jr rs jumps to whatever address a register holds. It is not a special “return” instruction. It becomes a only because $ra holds what jal put there. Here is the one that ends main:

jr ra at the end of main (0x03E00008 at 0xBFC00208)

Which field names the register, and why is everything else zero?

3126
opcode6b
000000
0 = SPECIAL
2521
rs5b
11111
$ra ($31)
2016
rt5b
00000
0
1511
rd5b
00000
0
106
sa5b
00000
0
50
funct6b
001000
8 = jr
binary00000011111000000000000000001000
hex0x03e00008one hex digit = four bits; a digit that spans two fields has two colors
asmjr $raR-format
Hover or focus a field to see its bits, value and role.

What to notice

R-format, opcode 0, funct 8. Only rs is used: 31, $ra. No target is in the word at all; the address lives in the register. jr $t9 would be the same word with rs = 25.

Before reading on, decide:

A function calls another function with jal, then returns with jr $ra. What must it do in between, and why?

Go deeper: how Carolyne computes jumps and links, and why the link is PC + 8

Carolyne’s branch unit treats jumps as branches that are always taken. The target of j/jal is (npc & 0xF0000000) | (index << 2), where npc is the delay slot’s address carried in the station entry; jr/jalr take the target from rs. The link value written by jal, jalr, bltzal and bgezal is pc + 8, computed from the instruction’s own PC in the same entry, and written to $ra (or rd) through the unit’s one destination slot, gated so that a plain j or jr writes nothing.

Why +8 and not +4? Because when the branch takes effect, the slot has already been fetched and will complete. If the link pointed at the slot, a return would run the slot a second time. Every MIPS link is therefore two instructions past the jump, and that number is the delay slot showing through in the architecture.

Can you now explain it?

j and jal replace the low 28 bits of the PC with a 26-bit index times 4; the top four bits stay. jal also writes $ra = its address + 8. jr $ra returns; jalr calls through a register.

If you remember only three things

  1. A jump names a word in its region. Index × 4, region from PC + 4. Any function in a 256 MB block is reachable; further needs lui, ori and jalr.
  2. The link is +8 because of the slot. The instruction after jal runs on the way out, so the return lands one word later.
  3. jr $ra is a plain register jump. It returns only because $ra still holds what jal wrote. A function that calls others must save $ra first.

Now try to explain this one yourself: the smoke program of §1.2 could have called its print code with bal instead of jal. What would be the same, and what would differ in the word?

Go deeper: a model answer, once you have tried

The same: $ra = the call’s address + 8, the delay slot runs, and jr $ra returns. The word differs completely: bal is bgezal $zero,label, an I-format REGIMM word whose 16-bit field is a signed distance in instructions from the slot, reaching ±128 KB. jal is a J-format word whose 26-bit field is an absolute index inside the 256 MB region. Within a small program both reach everything; a linker prefers jal because it never depends on the distance.

Check your understanding

0/5 answered
  1. 1.`0x0FF00063` at 0xBFC0008C is a jal. Where does it go?

  2. 2.After `jal main` at 0xBFC0008C executes, what does $ra hold?

  3. 3.Why does `jr ra` at the end of a function return to the caller?

  4. 4.Can `j` reach any address in memory?

  5. 5.What is `jalr $t9` for, and what does it write?


Next: §5.4 — the branch delay slot.

Where this comes back

3 later sections build on this one.