Branches and Jumps
Branches use PC-relative mode to find their target address. Jumps use direct mode.
We need to see how these address modes differ.
Here is some code with branches and jumps sprinkled around in it.
The column of comments contains plausible addresses for each of the instructions.
Notice that they all have the same target address: 0x00400048
add $3 $4 $5 # 0x00400000
beq $1 $2 place # 0x00400004
add $3 $4 $5 # 0x00400008
add $3 $4 $5 # 0x0040000C
j place # 0x00400010
add $3 $4 $5 # 0x00400014
add $3 $4 $5 # 0x00400018
add $3 $4 $5 # 0x0040001C
beq $1 $2 place # 0x00400020
add $3 $4 $5 # 0x00400024
add $3 $4 $5 # 0x00400028
add $3 $4 $5 # 0x0040002C
j place # 0x00400030
add $3 $4 $5 # 0x00400034
add $3 $4 $5 # 0x00400038
add $3 $4 $5 # 0x0040003C
add $3 $4 $5 # 0x00400040
add $3 $4 $5 # 0x00400044
place: add $3 $4 $5 # 0x00400048
We will assemble the branches into hexadecimal.
- PC-relative mode adds an offset to the program counter
- by the time this happens, the program counter has advanced to point to the instruction
after the branch
- the times-4 trick is in play, so the offset is a count of words, not bytes
We will simulate this by hand.
- Start counting at the instruction following the first branch and go to the target. I get 16
- The box looks like this
So the hexadecimal is 0x10220010. If that's a problem for you, consult the "Real Branches" web page.
- Start counting at the instruction following the second branch and go to the target. I get 9
- The box looks like this
So the hexadecimal is 0x10220009. If that's still a problem for you,
consult the "Real Branches" web page again.
Now let's do it as the assembler does it
- we need to subtract the address of the instruction after the branch from the address of the target
- that is, we need to compute targetAddress - (branchAddress + 4)
- removing the parentheses (5th grade, 6th grade? I forget) gives us targetAddress - branchAddress - 4
- start by computing 0x00400048 - 0x00400004 = 0x44
- now subtract the extra 4 and we get 0x40
- divide by 4 to take care of the times-4 trick; that gives us 0x10 or 16 decimal
- that's the same thing that we got when we counted by hand; fancy that!
- and the rest follows exactly as when we did it by hand
- now let's do the second branch
- start by computing 0x00400048 - 0x00400020 = 0x28
- now subtract the extra 4 and we get 0x24 = 36 decimal
- divide by 4 to take care of the times-4 trick; that gives us 9 decimal
- that's the same thing that we got when we counted by hand; fancy that!
- and the rest follows exactly as when we did it by hand
Now let's assemble the jumps into hexadecimal.
- direct mode just stuffs its address value into the program counter instead of adding to it
- that means that we just put the target address into the instruction
- however, the times-4 trick is also in play here, so we need to divide the target address by 4 first
- in both of our cases the target address is 0x00400048; dividing that by 4 gives us 0x00100012
- that's what we put into the 26-bit address field of both jump instructions
- The box looks like this
So the hexadecimal is 0x08100012. If that's a problem for you,
consult the "Jumps Use Direct Mode" web page.
Here are some things that should jump out at you:
- jumps with the same target are exactly the same wherever they are
- branches with the same target have different offsets depending on where they are,
so they will be different in each location
Notice that the example code for this page begins at address 0x00400000,
which is the same place that MARS begins the text segment.
That means that you can copy this code and paste it into MARS
to verify all the calculations that we did here.