What is the difference between unconditional branch and unconditional jump (instructions in MIPS)?

前端 未结 4 1802
青春惊慌失措
青春惊慌失措 2020-12-13 04:01

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条回答
  •  囚心锁ツ
    2020-12-13 04:24

    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.

    jump 0001 0010 0011 0100 0101 0110 0111 1100
    jump 0001 0010 0011 0100 0101 0110 0111 1100
    0000 1000 1000 1101 0001 0101 1001 1111 #in machine code # jump op = 0000 10
    When we execute this we take
    00 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 
    Then we AND the PC (where we're executing from) and 0xf0000000

    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.

提交回复
热议问题