CS222 Lecture: Arithmetic, Logical, and Data Movement Instructions      1/15/99

Need: Transparencies of VAX instruction set from programming card
      MIPS instruction set from inside back cover of book

Introduction
------------

   A. We now turn to a study of the VAX instruction set.  Since there are over
      300 instructions in the VAX machine language, this will take some time!
      Fortunately, the instructions fall into families of similar instructions,
      so that once one member of the family is learned many others are known, 
      too. (Actually, we won't attempt to cover all of them.)   We will also 
      look, for comparison purposes, at the corresponding instructions in the 
      MIPS instruction set - a much smaller set!

   B. The instructions we consider today are used for things like:

      1. Data movement (copying) between memory locations and/or registers

      2. Arithmetic operations

   C. All the instructions have both a direct and an indirect result:

      1. The direct result is to copy or compute some value and put it in
         some memory location or register - called the DESTINATION

      2. The indirect result is to set some or all of the CPU condition codes.
         The exact rule for setting these varies from instruction to 
         instruction, but is consistent with the basic meaning:

         Z = 1 iff result is zero
         N = 1 iff result < 0
         V = 1 iff signed overflow occurred
         C = 1 iff unsigned overflow/borrow occurred

   D. As we learn these instructions, we will also learn DEC's standard
      documentation format for them, which is used in the VAX programming card.

      TRANSPARENCY - go over ADDL2, ADDL3 noting

      1. Operands specified by name.access type
 
         access = r, w, m + others to be learned later
         type   = b, w, l, q, o, f, d, g, h + others
         Note: when a register is used as an operand, the following rules apply:
          b - affects only lower 8 bits
          w - affects only lower 16 bits
          l, f - affects whole register
          q, d, g - use two successively numbered registers
          o, h - use four successively numbered registers

       2. Condition code setting

          . = conditionally set or cleared as appropriate
          0 = always cleared
          1 = always set
          - = unchanged from previous value

I. Data Movement Instructions
-  ---- -------- ------------

   A. MOVx

      1. Type can be any integer or floating type, plus others to be learned 
         later.

      2. Z, N set conditionally; V always cleared (overflow cannot occur)
         C is irrelevant so is left unchanged

   B. CLRx

      1. Type can be any integer or floating type.

      2. Z = 1, N = 0 because result is 0; V always cleared (overflow cannot 
         occur) C is irrelevant so is left unchanged

   C. MNEGx

      1. Type can be any integer type EXCEPT quadword or octaword, or any
         floating type.  (This is typical of most of the rest of the
         instructions we will learn; quadword and octaword operations are
         quite limited.)

      2. For integers, negation is two's complement.

      3. Z and N set based on final result.  V is always 0 for reals, but
         can be either 0 or 1 for integers.  

         (ASK class how overflow can occur when negating an integer)

         C is set for integers as if the number was SUBTRACTED FROM ZERO -
         i.e. there was borrow out.  This is used for multiple precision
         integer operations, as we shall see later.

   D. CVTxy

      1. These operations perform a conversion from one data type to another.
         The instruction name includes the from type and the to type - e.g.

         CVTBF - converts a byte integer to a floating point real.

         (Note: integer types are always treated as SIGNED).

      2. These conversions are of several general types:

         integer -> wider integer:      Done by sign extension.  (I.e. the extra
                                        bits in the destination will be a copy
                                        of the sign bit of the source.)
         integer -> narrower integer:   Done by truncation of high bits -
                                        can overflow
        
         real -> wider real:            Done by adding low order 0's
         real -> narrower real:         Done by truncation of low mantissa bits-
                                        can overflow if destination type has a
                                        smaller number of bits for EXPONENT

         integer -> real:               Never overflows, but precision may be
                                        lost (e.g. a long has equivalent of
                                        10 decimal digits of precision, but
                                        a float has only 7.)

         real -> integer:               Done by truncation of fraction.  Can
                                        overflow if exponent is too big.

      3. The N and Z condition codes are set as always.  V is set if value
         of the source cannot be represented in target format.  C is always
         cleared, since operation is regarded as being done on signed
         numbers.

   E. CVTRxy

      1. This instruction is similar to CVTxy, but is available only for
         conversion of real types to longword integer.  

      2. The fractional part of the real number is ROUNDED instead of being
         truncated.

   F. MOVZxy

      1. This instruction is similar to CVTxy, but is available only for
         conversion of a narrower integer type to a wider integer type
         (e.g. Byte to Long).

      2. This operation treats the operand as an UNSIGNED number, so the 
         conversion is done by filling the high-order bits with zeroes, rather
         than by sign extension.

II. Arithmetic Instructions
--  ---------- ------------

   A. INCx

      1. Available only for byte, word, long integers.

      2. Equivalent to ADDx #1 - but shorter and faster

      3. N and Z are set as always.  V is set if 7F..F is incremented to
         80..0.  C is set if FF..F is incremented to 0.

   B. DECx

      1. Available only for byte, word, long integers.

      2. Equivalent to SUBx #1 - but shorter and faster

      3. N and Z are set as always.  V is set if 80..0 is decremented to
         7F..F.  C is set if 0 is decremented to FF..F.

   C. ADDx2, ADDx3, SUBx2, SUBx3

      1. Available for byte, word, long integers and any real type.
         For integers, result is correct both for signed and unsigned.

      2. N and Z are set as always.  V is set if SIGNED overflow occurs, and
         C is set if UNSIGNED integer overflow occurs.  C is always set to 0
         for real data types.

   D. ADWC, SBWS

      1. These instructions are equivalent to ADDL2, SUBL2, except that the
         value of the C bit BEFORE the instruction is executed is added or
         subtracted from the final result.

      2. These instructions are used to provide for multiple-precision 
         arithmetic.

         Example: To add the quadword integer A to the quadword integer B,
                  we would use:

                  ADDL2         A, B
                  ADWC          A+4, B+4

                  (Note: A, B are the addresses of the low order longwords
                         of the operands, A+4 and B+4 are the addresses of
                         the high order longwords.)

   E. MULx2, MULx3

      1. Available for byte, word, long integers and any real type.
         For integers, result is based on SIGNED operands.

      2. N, Z, and V are set as always.  (Note that overflow is very easily
         possible with this operation.)  C is always set to 0, since the
         operation always assumes signed numbers.

   F. DIVx2, DIVx3

      1. Available for byte, word, long integers and any real type.
         For integers, result is based on SIGNED operands.

      2. For integer division, the result is truncated toward zero - e.g.

         7 / 2          => 3
         7 / -2         => -3
         -7 / 2         => -3
         -7 / -2        => 3

         For floating divide, the result is rounded.

      3. N, Z, are set as always.  V is set if overflow occurs, which can
         happen as follows:

         a. Division by zero is attempted.  (This also causes an exception)

         b. 80..0 is divided by -1.

         c. A real divisor has a negative exponent (i.e. represents a fraction),
            and the result exponent is too large
         
         C is always set to 0, since the operation always assumes signed numbers

III. Byte Operations
---  ---- ----------

   On most computers, including the VAX, the data type BYTE is used to store 
   individual characters, and arrays of byte are used for character strings.

   A. Individual characters can be manipulated by operations such as MOVB.

   B. Character comparisons can be done using CMPB, which follows the
      ordering of ASCII codes.  This gives:

        ' ' < '0' < '9' < 'A' < 'Z' < 'a' < 'z' 
        (With punctuation interspersed throughout.)

   C. Character strings are sequences of characters in adjacent memory
      locations.

      1. The lowest addressed location contains the leftmost character ..
         the higest addressed location contains the rightmost character.

      2. The VAX has special instructions for manipulating character strings;
         however, covering them is beyond the scope of this course.

      3. For now, we can use byte operations in a loop to process the
         elements of a string one by one.

   D. VAX MACRO has several directives that can be used to create strings.

      1. .ASCII - constant string

         Example:       .ASCII  /ABC/

                        43 42 41 <- first byte

      2. .ASCIZ - constant string terminted by a null byte

         Example:       .ASCIZ  /ABC/

                     00 43 42 41 <- first byte

      3. .ASCID - constant string plus descriptor

         Example:       .ASCID  /ABC/

         system type info -> 010E 0003 <- length (word)
                             address ------
                              43 42 41  <--|

IV. Bit Manipulation Instructions
--  --- ------------ ------------

   A. Though the smallest unit of data that has its own address is the byte,
      there are times when we need to be able to manipulate individual
      bits.

   B. The MCOMx instruction moves a value with all its bits complemented.

      Example:  MCOML   #F7318420, R0           R0 becomes 08CE7BDF

   C. The BISx, BICx, XORx, and BITx instructions manipulate bits by using
      a MASK operand containing 1's in the bit positions that are to be
      affected and 0's in the bit positions to be left alone.

      1. BIS - bit set - turns selected bits on (1)

      2. BIC - bit clear - turns selected bits off (0)

      3. XOR - exclusive or - toggles selected bits (0->1 or 1->0)

      4. BIT - bit test - test selected bits (by a logical and with mask)

         Z is set if ALL selected bits are 0

         N is set if sign bit is 1 in BOTH mask and operand being tested

   D. Examples of usage

      1. Pascal sets

         type
                flavor = (chocolate, vanilla, strawberry, mint_chip);
                flavorset = set of flavor;

         var
                s, t, u: flavorset;

         This set is represented by a CHARACTERISTIC VECTOR of 4 bits (the
         low order 4 in a byte.)
                ______________
                /////| | | | |
                --------------
                (not  ^ ^ ^ ^
                used) | | | |___ 1 if chocolate is in the set
                      | | |_____ 1 if vanilla is in the set
                      | |_______ 1 if strawberry is in the set
                      |_________ 1 if mint_chip is in the set
                
         s := s + [vanilla];            BISB #2, S

         s := s - [strawberry];         BICB #4, S

         if chocolate in s then         BITB #1, S
                something               BEQL --------
                                        something   |
                                           <---------

         u := s + t;                    BISB3 S,T,U

         u := s - t;                    BICB3 T,S,U

         u := s * t;                    MCOMB T, R0
                                        BICB3 R0, S, U

      2. Working with IO devices

         a. Each VAX IO device has a COMMAND AND STATUS register (CSR) which has
            an address on the system bus, plus one or more data registers.

         b. One bit in the CSR is called the READY bit.  When it is 1, the
            device is ready for a new operation; when 0, the device is still
            busy with the previous operation.  This is normally bit 7 - i.e.
            the upper bit of the first byte of the CSR.

         c. Example: wait for device MYTTY to be ready to print a character,
                     then send one to it from R0

                1$: BITB        #^X80, @#MYTTY_CSR
                    BEQL        1$
                    MOVB        R0, #@MYTTY_DATA

V. Shift/Rotate Instructions
-  ------------ ------------

   A. ASHL, ASHQ

      1. For multiplying or dividing an integer by a power of 2, it is faster
         to shift the number left or right, rather than to use the regular
         multiply or divide instruction.

                                     n
         a. To multiply a number by 2  (n >= 0), shift if left n places.
                                   n
         b. To divide a number by 2  (n >= 0), shift if right n places.

         c. The ASHL and ASHQ instructions do this

      2. These instructions have three operands: The number of places to
         shift (positive implies left, negative right), the number to be
         shifted, and the destination where the result is to be stored.

      3. On a right shift, the sign bit is propagated - e.g. 

                40000000 shifted right becomes 20000000

                80000000 shifted right becomes C0000000

      4. On a right shift of a negative number, the result is NOT always
         the same as what one would get by using DIV with the corresponding
         power of 2

         Example:       FFFFFFFF (-1) shifted right one place becomes FFFFFFFF
                        FFFFFFFF div 2 would become 00000000

      5. Overflow occurs if, on a left shift, the bit shifted out of the
         sign is not the same as the bit shifted into the sign.  (This
         corresponds to a change of sign.)

      6. N and Z are set as always; C is cleared.
 
   B. ROTL
        
      1. This instruction is useful for bit manipulation.  The instruction is
         similar to ASHL, except the operand is ROTATED - i.e. the bit
         shifted out one end comes in the other end.

         Example:       80000000 rotated left becomes 00000001

      2. N and Z are set as always; V is cleared because the concept of
         overflow is meaningless for this operation; C is left alone.

VI. Equivalent MIPS instructions
--  ---------- ---- ------------

   A. The contrast between RISC and CISC architectures becomes very clear when
      we compare the VAX instructions we have learned and their MIPS
      equivalents.  First, some general comments about MIPS:

      1. Like the VAX, byte addressable with a 32 bit address => 4 GB address
         space (but no separation into spaces as on the VAX).

      2. Like the VAX, 32 bit registers.

         a. However, MIPS has 32 registers - known as $0 .. $31.

         b. Like the VAX, some of the the MIPS registers have special roles;
            but the roles are assigned by software conventions, not by being
            "hardwired" into the hardware.  These roles are represented by
            alternate names given to some of the registers (as used in the 
            text).

         c. Unlike the VAX - but a common convention on RISC's - register 0
            is hardwired to always contain the value zero.  Thus, it cannot
            be used as a destination for an operation, and always supplies
            the value zero when used as a source.

   B. Arithmetic-Logic Instructions

      1. In contrast to the VAX, MIPS arithmetic-logic instructions only
         operate on values in registers - never in memory, and always have
         three operands (dest, source1, source2 - note reverse of VAX order!)
         (Source2 can be either a register or a 16-bit immediate value 
         contained in the instruction itself.)

      2. In contrast to the VAX, integer operations on MIPS always work on
         a 32-bit word - there are no byte, etc. variants.  Floating point
         operations are done by a co-processor; its instructions have two 
         variants - one for single precision and one for double, as opposed to 
         four on the VAX.

      3. VAX instructions can vary greatly in length - from as little as one
         byte to as dozens.  MIPS instructions are always 32 bits long.

         Example: VAX:  INCL R1         50 D6

                  MIPS  addi $1, $1, 1  20210001

                  (Note how the general add instruction must be used)

         Example: VAX:  ADDL3 @#X, @#Y, @#Z  (Assume X at 1000, Y 1004, Z 1008)

                        00001000 9F 00001004 9F 00001008 9F C1

                  MIPS: No single instruction equivalent

      4. Much smaller set of instructions: The complete set is in inside
         back cover of text!

         TRANSPARENCY

         NOTE: One thing MIPS has that VAX does not is unsigned variants
               of multiply, divide.

   C. Data movement instructions

      1. In contrast to the VAX MOV instruction which can move a value from
         any kind of source (memory, register, immediate) to any kind of
         destination (memory, register), MIPS data movement instructions always
         move a value between a register and memory, and are of two kinds:

         a. Load: memory to register

         b. Store: register to memory

      2. Whereas the VAX has variants of the move instruction that do various
         data type conversions, negation, etc, the only data conversions done
         by MIPS instructions are widening to a word (if necessary) on load
         and narrowing (if necessary) on store.   (The register operand is
         always treated as a 32 bit value).

      3. Again, MIPS instructions are always 32 bit.             

      4. Again, a very small set.

         TRANSPARENCY

         (NOTE: MIPS also has lh, lhu, sh - not shown in book).

   D. The effect of instructions that are present on the VAX but not on MIPS 
      can be achieved by an appropriate use of some other instruction or by
      a sequence of instructions.

      1. Example: VAX MOV between registers can be done by MIPS add with $0
         as second source

         VAX:   MOV     R1, R2

         MIPS:  add     $2, $1, $0

      2. Example: VAX CLR can be done by MIPS add with $0 as both sources
         (clear register) or MIPS sw with $0 as source (clear memory)

         VAX:   CLR     R1
                CLR     X

         MIPS:  add     $1, $0, $0
                sw      $0, X

      3. Example: VAX MNEG can be done by MIPS sub with $0 as first source

         VAX:   MNEG    R1, R2

         MIPS:  sub     $2, $0, $1

      4. Example: VAX INC, DEC can be done by MIPS addi with +1/-1 as second
         operand

         VAX:   INCL    R1
                DECL    R2

         MIPS:  addi    $1, $1, 1
                addi    $2, $2, -1

      5. Example: VAX arithmetic/logic operations on memory require a load,
         compute, store sequence on MIPS

         VAX:   ADDL3   X, Y, Z

         MIPS:  lw      $1, Y
                lw      $2, Z
                add     $1, $1, $2
                sw      $1, X

         (But a good compiler will keep key variables in registers, avoiding
          need for trips to memory.  Since MIPS has twice as many registers
          as the VAX, this is easier to do on MIPS.)

Copyright ©1999 - Russell C. Bjork