Four jumps
A has no test. It always goes.
| instruction | goes to | also | used for |
|---|---|---|---|
j target | the 26-bit index, in this region | — | far unconditional jumps |
jal target | the same | $ra = its address + 8 | calling a function |
jr rs | the address in rs | — | returning (jr $ra), switch tables |
jalr rd,rs | the address in rs | rd = 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?
From the index 0x3F00063 to the target 0xBFC0018C
Where do the top four bits come from?
0x0ff00063 at 0xbfc0008c: jal 0xbfc0018c
- 1. the 26-bit index field, bits 25–0 of the word0x03f0006300000011111100000000000001100011
jal 0xbfc0018c: everything below the opcode is one number, 0x3f00063.
- 2. multiply by 4 (shift left by 2): 28 bits0x0fc0018c
- 3. the top 4 bits of PC + 40xb0000000
- 4. target = region | index × 40xbfc0018c
- 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.
The link: $ra = jal + 8
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 → | 0xbfc00000 | 0x3c191000 | _start:lui $t9,0x1000 |
| 0xbfc00004 | 0x37390ff0 | ori $t9,$t9,0xff0 | |
| 0xbfc00008 | 0x24040041 | li $a0,65 | |
| 0xbfc0000c | 0x0ff00009 | jal 0xbfc00024 | |
| 0xbfc00010 | 0x00000000 | nop | |
| 0xbfc00014 | 0x24040042 | li $a0,66 | |
| 0xbfc00018 | 0x0ff00009 | jal 0xbfc00024 | |
| 0xbfc0001c | 0x00000000 | nop | |
| 0xbfc00020 | 0xaf200008 | sw $zero,8($t9) | |
| 0xbfc00024 | 0xaf240000 | put:sw $a0,0($t9) | |
| 0xbfc00028 | 0x03e00008 | jr $ra | |
| 0xbfc0002c | 0x00000000 | nop |
registers — read · written this tick
console (what the doors printed)
▮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?
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
- 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.
- The link is +8 because of the slot. The instruction after jal runs on the way out, so the return lands one word later.
- 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 answered1.`0x0FF00063` at 0xBFC0008C is a jal. Where does it go?
2.After `jal main` at 0xBFC0008C executes, what does $ra hold?
3.Why does `jr ra` at the end of a function return to the caller?
4.Can `j` reach any address in memory?
5.What is `jalr $t9` for, and what does it write?
Next: §5.4 — the branch delay slot.