"Large" numbers and "small" numbers

  • Difference between large and small numbers:

    • Large numbers require more digits to represent their value

  • Example:

      We can use 8 bits to represent the value  2  in binary:
    
                 00000010
    
      We can use at least 11 bits to represent the value  1024 = 210  in binary:
    
                 00000100 00000000
    

  • Integer values can range between:

            −2147483647 (−231-1)   to    2147483648 (231)
    

    Integer values require 32 bits for representation !

Why ARM cannot store a 32 bits number into a register with one instruction

Why the ARM process cannot store a 32 bits (binary) number into a register with 1 instruction:

  • ARM instructions are 4 bytes or 32 bits long:
       <------------------------------ 32 bits ----------------------->
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
    

  • To represent a 32 bits (binary) number, you need to use 32 bits:
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
    


  • ARM cannot use 1 instruction: to move a 32 bits number to a register because:

    • The ARM instruction would have no space left to encode/represent the operation code !!!

ARM must use two instructions (movw and movt) to move a 32 bits binary number into a register

The movw ARM assembler instruction

  • Syntax of the movw instruction:

       movw  rN, #x   // x = a value between 0 .. 216-1 
    

    Effect:

    1. Store the 16 bits binary number x in the lower 16 bits of the register rN
    2. Clear the upper 16 bits in the register rN

  • Example:

             +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       R0 =  |1|0|1|0|1|0|1|0|1|0|1|0|1|0|1|0|1|0|1|0|1|0|1|0|1|0|1|0|1|0|1|0|
             +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
      
       After executing  movw R0,#15  (15 = 0000000000001111 in 16 bits)
      
             +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       R0 =  |0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|1|1|1|
             +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
        

DEMO: /home/cs255001/demo/asm/2-mov/movw.s

The movt ARM assembler instruction

  • Syntax of the movt instruction:

       movt  rN, #x   // x = a value between 0 .. 216-1 
    

    Effect:

    1. Store the 16 bits binary number x in the upper 16 bits of the register rN
    2. Leave the lower 16 bits in the register rN unchanged

  • Example:

             +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        R0:  |1|0|1|0|1|0|1|0|1|0|1|0|1|0|1|0|1|0|1|0|1|0|1|0|1|0|1|0|1|0|1|0|
             +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
      
       After executing  movt R0,#15  (15 = 0000000000001111 in 16 bits)
      
             +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        R0:  |0|0|0|0|0|0|0|0|0|0|0|0|1|1|1|1|1|0|1|0|1|0|1|0|1|0|1|0|1|0|1|0|
             +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
        

DEMO: /home/cs255001/demo/asm/2-mov/movt.s

How do we use movw and movt to store a 32 bits number into a register

  1. We break the 32 bits binary number into 2 (equal) halves:

         <------------- 32 bits binary number ---------->
        +-----------------------+-----------------------+ 
        | most significant bits | least signficant bits |
        +-----------------------+-----------------------+
         <-- 16 bits bin num --> <-- 16 bits bin num -->
      

  2. First: use the movw instruction to move the least significant 16 bits into the register:
          <------------- 32 bits binary number ---------->
         +-----------------------+-----------------------+ 
         | most significant bits | least signficant bits |
         +-----------------------+-----------------------+
          <-- 16 bits bin num --> <-- 16 bits bin num -->
    

  3. Then: use the movt instruction to move the most significant 16 bits into the same register
          <------------- 32 bits binary number ---------->
         +-----------------------+-----------------------+ 
         | most significant bits | least signficant bits |
         +-----------------------+-----------------------+
          <-- 16 bits bin num --> <-- 16 bits bin num -->
    

How do we use movw and movt to store a 32 bits number into a register

  • Example: move the value 65540(10) (= 0000000000000001 0000000000000100) into reg r0:

            +---------------------------------+ 
       R0 = | 00000000000000010000000000000100|
            +---------------------------------+
             <--- 16 bits ---><--- 16 bits --->
      

  • First: use the movw r0, #4 instruction to move 0000000000000100 into r0:
          +---------------------------------+ 
     R0 = | 00000000000000000000000000000100| // Note: the upper 16 bits are incorrect
          +---------------------------------+
           <--- 16 bits ---><--- 16 bits --->
    

  • Then: use the movt r0, #1 instruction to move 0000000000000001 into the same register
          +---------------------------------+ 
     R0 = | 00000000000000010000000000000100| // R0 = 65549 !!!
          +---------------------------------+
           <--- 16 bits ---><--- 16 bits --->
    

Assembler support for the movw and movt instructions

The ARM assembler provides 2 operators to help you use the movw and movt instructions:

  • The :lower16: operator:

        :lower16:x  ≡  x % 216 

    The :lower16: operation will return the lower 16 bits of a number


  • The :upper16: operator:

        :upper16:x  ≡  x / 216 

    The :upper16: operation will return the upper 16 bits of a number

How do we move (= put) a large (binary) number into a register

 Suppose we have arbitrary 32 bits number X:

          X = UUUUUUUUUUUUUUUULLLLLLLLLLLLLLLL 
              ^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^
               upper 16 bits    lower 16 bits


We store X into register r0 using the 2 assembler instructions: +----------------------------------+ r0 = | 32 bits | +----------------------------------+ | movw r0, #:lower16:X | V +----------------------------------+ r0 = | 0000000000000000LLLLLLLLLLLLLLLL | +----------------------------------+ | movt r0, #:upper16:X | V +----------------------------------+ r0 = | UUUUUUUUUUUUUUUULLLLLLLLLLLLLLLL | = X !! +----------------------------------+

Example: storing a large number into a register

  • Problem:

      • Store the number 1234567 (decimal) into register R0         

  • Incorrect way:

       mov   r0, #1234567   // Illegal value for mov    
      

  • Correct solution:

       movw  r0, #:lower16:1234567  // 1234567 % 216 = 54919 
       movt  r0, #:upper16:1234567  // 1234567 / 216 = 18 
      

DEMO: /home/cs255001/demo/asm/2-mov/mov-large.s