You may look into Wikipedia or short summary for students. Everybody says that there are two instructions for the same thing. But nobody tells why?
4 Answers
Branches allow for conditions. But allowing for conditions takes up more bits in the instruction. Therefore, a branch's address is only 2^16 bits and only allows you to branch 2^15 - 1 instructions backward or 2^15 instructions forward.
A jump is unconditional and the bits saved by leaving out the condition can be used for the address. A jump allows for a 26 bit address and so can jump much further in the code than a branch. At the expense of not being conditional.
As already mentioned, branch has fewer bits, a shorter range and is relative. Jump has more bits and is absolute.
Take this example
b l0
nop
beq $0,$1,l1
nop
j l2
nop
l0: .word 0,0
l1: .word 0,0
l2: .word 0,0
and you get this
00000000 <l0-0x1c>:
0: 10000006 b 1c <l0>
4: 00000000 nop
8: 10010006 beq zero,at,24 <l1>
c: 00000000 nop
10: 0800000b j 2c <l2>
14: 00000000 nop
18: 00000000 nop
0000001c <l0>:
...
00000024 <l1>:
...
0000002c <l2>:
...
now what the other answers may not have mentioned is that the unconditional branch is encoded, at least by gnu assembler, as a branch if equal, with the same register. There is no unconditional branch in mips, there is branch if equal and branch if not equal from what I can tell.
You see above the jump uses a 0xB which is the word address, 0xB*4 = 0x2C the address of the destination, where the conditionals use relative addressing pc+(signed_offset*4) where the pc=instruction_address+4; Or take instruction_address + 4 + (signed_offset*4) to get the destination address.
Using the alias b for branch instead of j for jump will create position independent code. Jump will not, have to re-link if you move around, for near jumps probably better to use branch instead of jump even though it is an alias. If you are a purist then you can use the real instruction beq $0,$0,label or pick any register beq $4,$4,label. register 0 being special and fast may be the better choice.
A jump and unconditional branch, in MIPS, are not the same.
Both branch and jump instructions write data to the Program Counter register so that upon the next fetch cycle, a different instruction will be fetched instead of the next instruction in line in program memory. In that sense, they carry out the same type of operation.
Where they differ is that branches are conditional, they only change the next instruction to be executed if a certain condition is met. This can be illustrated by the difference in execution code in an if
statement or by calling a function.
if (a == 0) {
a = 1
}
setAtoOne()
The if
statement jumps to the instruction to set a = 1
only if a == 0
. The function will jump to that instruction regardless.
In this case, we're talking about a branch where the condition is always true. It's just another way of writing
beq $zero, $zero, (int)offset
$zero is always equal to $zero, so it always branches to the specified offset. It's like this if statement
if (true) { a = 1 }
There is another difference between branch and jump instructions. Jump instructions specify an absolute address which the PC will be set to, whereas branch instructions offset the address in the program counter.
PC = 32-bit address # Jump
PC += 16-bits lower
In actuality, this is not strictly true. We write assembly with absolute addresses and offsets but in both jumps and branches it gets compiled to an offset. This is why you can't jump or branch to anywhere in memory, expect using the jump to register jr
instruction. This is because of a fundamental design of MIPS, fixed length one word instructions.
All MIPS instructions are 1 word (ie 4 bytes/32-bits) long. They contain an id for instruction (called op-code) which is 6 bits along with other information needed to execute the instruction. This may be the id of registers or 'immediate' values, basically integers encoded in the instruction.
Each byte in memory in MIPS has an address in between 0x00000000
- 0xFFFFFFFF
. To get to one of those bytes we need to specify the address. If were lucky to store the address in a register we would just jr
and use the address already stored in register. However, we are not.
This becomes problematic, we only have 32 bits for our instructions and we would need all those bits to specify the address in that range. We also had to give up 6 bits to be used by the processor to identify the instruction. Now we are left with 26 bits.
What is worse is that when we branch, we need 10 additional bits to specify the two registers we are comparing for our condition. The solution is to use offsets.
Let's say that we are at address 0x12345678
and we are executing an unconditional jump to the next address in memory j 0x1234567c
. This is the assembly code and I'll show how this gets translated into machine code and executed.
First we cheat a little. We know instructions are one word (4 bytes) and in MIPS it's specified that they must be within the word boundary. This means that all instructions have addresses that are 4 bytes apart and this means they always end in 00 in binary representation. Great, we can shave off those two meaningless bits. We also shave of the first 6, but don't worry, we'll get them back later.
When we execute this we take
jump 0001 0010 0011 0100 0101 0110 0111 11
00
jump 0001 0010 0011 0100 0101 0110 0111 1100
0000 1000 1000 1101 0001 0101 1001 1111 #in machine code # jump op = 0000 10
Then we AND the PC (where we're executing from) and 0xf000000000 1000 1101 0001 0101 1001 1111
0000 0000 1000 1101 0001 0101 1001 1111 # extend >> 6
0000 0010 0011 0100 0101 0110 0111 1100 # << 2
0001 0010 0011 0100 0101 0110 0111 1000
1111 0000 0000 0000 0000 0000 0000 0000
AND
0001 0000 0000 0000 0000 0000 0000 0000
We know take the result of this and OR it with our instruction integer
0001 0000 0000 0000 0000 0000 0000 0000
0000 0010 0011 0100 0101 0110 0111 1100
OR
0001 0010 0011 0100 0101 0110 0111 1100
Which is 0x1234567c
in Hex and where we want to go, now we jump there. This is why you can't jump further than 256MB (2^28 bits) away from your current instruction (unless you jump to the value of a register jr
)
The same basic idea holds for branches, except now you also have the 2 registers being compared (which require 10 bits) so you only have 16 bits which you can use to offset, hence why you can't jump as far with branches.
Generally, this is fine because we mostly use branches within a procedure, to implement loops and carry out conditional assignments.
This is all a consequence of the design of the MIPS architecture. It would have been entirely possible to have instructions where the only difference between branches and jumps would have been the conditional aspects and where an 'unconditional' branch would have behaved the same as an unconditional jump.