CS311 Lecture: Program Control Instructions             Revised 9/11/03

Objectives:

1. To introduce the MIPS unconditional branching instructions - j, jr
2. To introduce the MIPS conditional branching instructions - beq, bne
3. To show how HLL control structures can be realized by branches
4. To show how to implement inequality comparisons using slt, slti

Materials: 

1. MIPS ISA Handout (they already have)
2. Handout on Translation of Control Structures

I. Introduction
-  ------------

   A. In our first intoduction to the execution cycle of a Von Neumann
      architecture computer, we met the Program Counter (pc) register - which
      always holds the address of the NEXT instruction to be fetched from
      memory and executed.

      1. In the standard fetch/execute cycle, the pc is updated after fetching
         an instruction to point to the next successive instruction.

      2. In the case of MIPS, this means adding 4 to the pc after each
         instruction is fetched, since all MIPS instructions are one word
         (4 bytes) long.

      3. Obviously, if this were the only way to update the pc, this would
         result in executing each instruction in the program once, from top
         to bottom without any variation - which would not usually be usefui.

   B. In HLL's such as C/C++ or Java , we typically have a number of constructs 
      for altering the order of program execution within a procedure - e.g.

                if (...) ... else ...
                switch (...) { case ... case ... case ... default ... }
                while (...) ...
                do ... while (...)
                for (...) ...
                goto ...        // C/C++ only - not Java 

   C. In machine language, regardless of the machine, we basically have only 
      two:

      1. The equivalent of goto ... - puts a new value into the pc, causing
         the next instruction to be fetched from that location.  This is
         called in various ISA's an UNCONDITIONAL BRANCH or a JUMP.

      2. The equivalent of if (...) goto - puts a new value into the pc
         if and only if some condition is true.  This is called CONDITIONAL
         BRANCH or simply BRANCH.

      3. Actually, we could make do with only the conditional form - we could
         get the effect of an unconditional branch by using a conditional
         branch with a condition that we guarantee to be true.   However,
         most architectures, including MIPS, provide both forms, because the 
         unconditional form is simpler and can be made more flexible.

II. MIPS Program-Control Instructions
--  ---- --------------- ------------

   A. Unconditional jumps - Two variants:

      1. j address      - Destination address is contained in instruction

         a. It looks like this (all values given in decimal)

                 # of bits      6       26

                 field name     op      target address

                 contents       op = 2  
                                for j
        
                 This general format of instruction is called J format (where J
                 stands for "jump"
         
         b. The jump instruction specifies the address of an instruction; this
            address is put in the pc in place of the value computed by adding
            4 to the address of the current instruction.

         c. The target address field in the instruction is only 26 bits long,
            which isn't long enough to specify an address anywhere in memory
            (for which a 32 bit address is required).  Two measures are used 
            to deal with this. 

            i. The target address specified in the instruction is multiplied by
               4.  Multiplication by 4 is done because instructions are words, 
               and therefore must have addresses that are a multiple of 4.  
               Doing this allows a 26 bit address to encode information that
               corresponds to the lower 28 bits of the pc.

           ii. The target address is loaded into the lower 28 bits of the pc,
               and the upper 4 bits are left alone.  This means that the
               jump must always be to an address in the same 256 MB chunk of
               memory as the instruction is in.  Since most programs are
               much smaller than 256 MB, this hasn't proved to be a serious
               problem - (yet!)

      2. jr register    - Destination address is contained in register

         a. It looks like this (all values given in decimal)

                 # of bits      6       5       5       5       5       6       

                 field name     op      rs      rt      rd      shamt   funct

                 contents       op = 0  reg     (not    (not    (not    8 for jr
                                for     that    used -  used -   used - 
                                most R  holds   0)      0)       0)
                                type    destination
                                instructons
        
                 (Note that this is an R format instruction, though most
                  of the fields go unused.)

         b. The contents of the specified register is placed in the pc, 
            becoming the address of the next instruction.  Multiplication
            by 4 is NOT done (not needed).

         c. With this format, any location in memory could be the destination,
            so it could be used in the case where j could not reach a desired
            destination - but this is rarely, if ever, an issue.

         d. More commonly, the jr is used for two cases, both of which
            require that the destination address of the branch be computed
            during program execution, rather than being hardwired into the
            code.

            i. In implementing switch instructions - discussed below

           ii. In implementing return from a procedure - discussed in the
               next series of lectures.

   B. Conditional

      1. The MIPS conditional branch instructions perform a comparison
         between two registers, and then take/don't take the branch
         conditioned on the result.  There are only two such instructions
         we will consider.  (There actually are a few more, especially in
         later versions of the ISA, but these are the two most generally
         useful ones.)

         a. beq - branch if the two registers are equal
        
         b. bne - branch if the two registers are not equal

      2. Both conditional branches are I format instructions, and look like
         this

         # of bits      6               5       5       16      

         field name     op              rs      rt      immediate value

         contents       op =            first   second  offset
                        4 for beq       reg to  reg to  (two's complement
                        5 for bne       compare compare  signed number)

      3. Both conditional branches specify the destination of the branch
         as an offset relative to the value currently in the PC.  

         a. The offset is multiplied by 4 (because all instruction addresses
            are a multiple of 4) and then added to the value currently in
            the pc, which is by this time the address of the NEXT instruction
            to be executed.

         b. The offset can range from -32678 to +32767.  After multiplication
            by 4, and adding to the address of the next instruction, this means 
            that conditional branches can "reach" to an instruction in the range

            address of branch instruction - 131068 ..
            address of branch instruction + 131072

III. Translating HLL Control Structures
---  ----------- --- ------- ----------

    A. We are now ready to see how some familiar HLL control structures
       can be translated into assembly/machine language.  

       1. To keep our focus on the control structures, we'll write the HLL 
          statements in terms of CPU registers - actually they would be written 
          in terms of HLL variables which have to be mapped/load into 
          registers, of course.

       2. Likewise, we'll specify the target addresses of the branch
          instructions symbolically - e.g.

                bne     $4, $5, L1
                ...
                ...
          L1:   some instruction

                will mean "put a target address into the branch instruction
                such that when it is multiplied by 4 and added to the address
                of the next instruction it will cause execution to continue
                at the instruction labelled L1:

          Example: Suppose the bne instruction is at address 0x1000, and the
                   instruction labelled L1 is at 0x100c - then the branch
                   instruction would be encoded as:

                 bits           31..26  25..21  20..16  15..0
                                (6)     (5)     (5)     (16)

                 field          5       4       5       2
                 values 
                 (decimal)

                 binary         000101  00100   00101   0000000000000010

                                = 0001 0100 1000 0101 0000 0000 0000 0010 

                 hexadecimal    =  0x14850002

                 The instruction contains 2 in the offset field because
                 the instruction following the branch is at 0x1004, and
                 0x1004 + (4 x 2) = 0x100c = desired target.

          (This is a computation that the assembler routinely does.)

       DISTRIBUTE CONTROL STRUCTURES HANDOUT

    B. Simple if (no else)

       Example: if ($4 == $5)
                    do something

                bne $4, $5, L1
                code for do something
       L1:      (next instruction after the if)

       (Note the inversion of the sense of the branch)

   C. If .. else

      Example:  if ($4 == $5)
                    do something
                else
                    do something else

                bne $4, $5, L1
                code for do something
                j L2
        L1:     code for do something else
        L2:     (next instruction after the if)
        (Note, again, the inversion of the sense of the branch)

   D. While loop

      Example:  while ($4 == $5)
                    do something

        L1:     bne $4, $5, L2
                code for do something
                j L1
        L2:     (next instruction after the while)

      or: (slightly more efficient - one less instruction in loop body)

                j L2
        L1:     code for do something
        L2:     beq $4, $5, L1


   E. Do .. while loop

      Example:  do
                    do something
                while ($4 == $5)

        L1:     code for do something
                beq $4, $5, L1

   F. For loop

      Example:  for ($4 = 0, $4 != $5, $4 ++)
                    do something

                sub $4, $4, $4
        L1:     beq $4, $5, L2
                code for do something
                addi $4, $4, 1
                j L1
        L2:     (next instruction after the for)

      or: (slightly more efficient - one less instruction in loop body)

                sub $4, $4, $4
                j L2
        L1:     code for do something
                addi $4, $4, 1
        L2:     bne $4, $5, L1

   G. Switch statement - two possible approaches

      1. Translate the switch as if it were a series of ifs:

         Example:       switch(x)
                        {
                            case v1:
                                code1;
                                break;
                            case v2:
                                code2;
                                break;
                            ...
                            default:
                                coded
                        }

                        lw $4, x
                        li $2, v1
                        bne $4, $2, L1
                        code1
                        j Lfini
                L1:     li $2, v2
                        bne $4, $2, L2
                        code2
                        j LFini
                L2:     ...
                Ln:     coded
                LFini:  

      2. The problem with the above is that we could be forced to do as
         many comparisons as there are cases - and on the average would
         do half.  If the set of case labels forms a dense set, with few or any
         missing values, then a much more efficient translation is possible
         using a JUMP TABLE.

         Example: We could translate the following switch statement as shown

                        switch(x)
                        {
                            case 0: 
                                code0;
                                break;
                            case 1:
                                code1;
                                break;
                            case 2:
                                code2;
                                break;
                            default:
                                coded;
                        }

                        lw $4, x
                        -- if $4 < 0 or $4 > 2 do coded (as above) then j LFini
                        -- multiply $4 by 4 (shift left two places)
                        lw $4, JTable($4)
                        jr $4

                JTable: Lcode0
                        Lcode1
                        Lcode2

                Lcode0: code0
                        j LFini
                Lcode1: code1
                        j LFini
                Lcode2: code2
                        j LFini

                LFini:

   H. Note that, on occassion, it may be necessary to translate an HLL
      construct circuitously, because of the limited range of the conditional
      branch instructions (though this will not happen often on a machine
      like MIPS because the range of the conditional branch is -32767/+32768
      INSTRUCTIONS.  It is conceivable that a problem could arise with the
      initial conditional branch at the start of a very large switch
      statement.

      1. Typical        if ($4 == 0) 
         example:           $4 = $5

                        bne     $4, $0, L1
                        move    $4, $5          # translated as add $4, $5, $0
                L1:     (instruction after if)

      2. Unusual        if ($4 == 0)
         example:           ... very long series of statements

        Might have to be translated as follows:

                        beq     $4, $0, L1
                        j       L2
                L1:     ... translation of long series of statements
                        ...
                L2

IV. Handling Comparisons for Other than Exact Equality
--- -------- ----------- --- ----- ---- ----- --------

   A. The conditional branches on MIPS allow us to compare two registers
      for exact equality - i.e. they correspond to the C/C++/Java operators
      == and !=.   What if we want to compare for inequality - i.e. we
      want the assembly language equivalents of >, >=, <, or <= ?

   B. The MIPS ISA uses auxillary instructions that set a register to 1 or 0
      based on comparison of two other values.

            slt  - compare two registers
            slti - compare a register to an immediate value

      1. The slt instruction has the following format in machine language:

         # of bits      6       5       5       5       5       6       

         field name     op      rs      rt      rd      shamt   funct

         contents       op = 0  1st     2nd     dest    (not    arith/logical
                        for     source  source  reg     used -  function =
                        most R  reg     reg              0)     42 for slt
                        type
                        instructons

         (Note: this is an R Format instruction)

         Example: slt $2, $4, $0

         bits           31..26  25..21  20..16  15..11  10..6   5..0     
                        (6)     (5)     (5)     (5)     (5)     (6)

         field          0       4       0       2       0       42
         values 
         (decimal)

         binary         000000  00100   00000   00010   00000   101010

                        = 0000 0000 1000 0000 0001 0000 0010 1010

         hexadecimal    =  0x0080102a

      2. The slti instruction has the following format in machine language:

         # of bits      6               5       5               16      

         field name     op              rs      rt              immediate value

         contents       op =            source  destination     value to compare
                        10 for slti     reg     reg             to (two's 
                                                                 complement
                                                                 signed number)
         (Note: this is an I Format instruction)

         Example: slti $2, $4, 42

          bits          31..26  25..21  20..16  15..0
                        (6)     (5)     (5)     (16)

         field          10      4       2       42
         values 
         (decimal)

         binary         001010  00100   00010   0000000000101010

                        = 0010 1000 1000 0010 0000 0000 0010 1010 

         hexadecimal    =  0x2882002a

      3. Example: suppose we want to calculate the absolute value of the
         number in register 4 - i.e. if the value in register 4 is less
         than 0, we want to negate it (by subtracting it from zero.)

         Assume we can use $2 as a temporary.
        
         a. One approach, using slt to compare $4 to $0 (always zero).

                slt     $2, $4, $0      # $2 = 1 iff $4 < 0
                beq     $2, $0, L1      # if $2 = 0. skip next instruction      
                sub     $4, $0, $4      # negate $4
         L1:

         b. A similar approach, but using slti to compare $4 to literal 0.

                slti    $2, $4, 0       # $2 = 1 iff $4 < 0
                beq     $2, $0, L1      # if $2 = 0. skip next instruction      
                sub     $4, $0, $4      # negate $4
         L1:

   C. With only a set if less than, how do we handle other comparison orders?

      ASK

      1. x < y          slt     temp, x, y
                        bne     temp, target

      2. x > y          slt     temp, y, x
                        bne     temp, target

      3. x <= y         slt     temp, y, x
                        beq     temp, target    (x <= y <=> not y < x)

      4. x >= y         slt     temp, x, y
                        beq     temp, target    (x >= y <=> not x < y) 

Copyright ©2003 - Russell C. Bjork