Saturday, April 20, 2024 | Toby Opferman
 

Assembly Tutorial Part 1

Toby Opferman
http://www.opferman.net
programming@opferman.net


                                        Assembly Tutorial
                                        
        Finally, I have decided to write an Assembly tutorial due to popular requests
and for lack of a better one on the web (Unless you count Art of Assembly).  This is 
by no means complete and it may not even help you at all.  I provide this tutorial with
hopes you may actually learn something, but it may make you even more confused.  
YOU HAVE BEEN WARNED!


                                      PART I. Number Bases

        A number base is a format to represent a value or number in.  The bases
are 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, etc.

        Everyday use, we use base 10.  In a base, you have "base" number of digits.
0, 1, 2, 3, 4, 5, 6, 7, 8, 9  <-- 10 digits in base 10.  Also, The "base" itself
cannot be represented in a 1 digit, it starts the next layer of digits:
10 <-- flips to 2 digits at 10.  Actually, it adds a new digit at each power of the base:

10    = 10^1
100   = 10^2
1000  = 10^3
10000 = 10^4    

Let us see for example, base 3.  We have 3 numbers: 0, 1, 2.  At 3, we flip to 2 digits:

10(b3)  <-- that is 3 in base 3.  [ We will use (bx) where x = base number to represent
                                    numbers not in base 10 ]
10(b3)   = 3^1 = 3                            
100(b3)  = 3^2 = 9
1000(b3) = 3^3 = 27

and so forth.  To represent a number in base 3, you start counting like normal.
0               0
1               1 
2               2 
10(b3)          3
11(b3)          4
12(b3)          5
20(b3)          6 
21(b3)          7
22(b3)          8
100(b3)         9

That's 1 - 9 using base 3.  Now, you ask if you have a number such as:

2120(b3)  How do you get the number in base 10?

Simple!    

Each place represents a power of the number. (ie)
base^n .... base^2 base^1 base^0

in 2120(b3) you have  2 = base^3, 1 = base^2, 2 = base^1, 0 = base^0

place holders.                

Example is in base 10:

313  3 = base^2, 1 = base^1, 3 = base^0

but base = 10 in this example

To get the number, you Multiple by base^position and add it to the rest:

3*10^2 + 1*10^1 + 3*10^0
3*100  + 1*10   + 3*1
300    +  10    +  3
= 313

* and so 313 base 10 = 313 base 10

Now, let's apply that to base 3's example:
in 2120(b3) you have  2 = base^3, 1 = base^2, 2 = base^1, 0 = base^0
2*3^3 + 1*3^2 + 2*3^1 + 0*3^0
2*27  + 1*9   + 2*3   + 0*1
54    + 9     + 6     + 0
= 69

* and so 2120(b3) = 69 base 10


Now, in computers and assembly, we never use base 3, so why did I show you this?

Well, a lot of people start to think that only certain numbers are bases.
In computers, you use base 2 and base 16 (on very rare and strange occasions base 8(Octal))
Some people forget that base conversions are general forms that apply to any base.


We will now be talking about base 2 (Binary).

In base 2, you have 0, 1.
0000      0  
0001      1  *
0010      2  *
0011      3
0100      4  *
0101      5
0110      6
0111      7
1000      8  *
1001      9
1010     10
1011     11
1100     12
1101     13
1110     14
1111     15

The 4 that I have put the * by are always important to remeber.
They are powers of 2.

You can add them up to get any of those numbers.

8421  <-- What ever bits are set, add their place values and get the number.

2^3 = 8, 2^2 = 4, 2^1 = 2, 2^0 = 1.

Remeber, all powers are starting at 0.

So, when ever later on you see bit layouts, they will say:

[ bit7 | bit 5-6 |  bit 3-4 | bit 2 | bit 1 | bit 0 ]

That is a byte, 8 bits.  But they are 0 indexed.

0-15 are important.  You should remeber what these look like, we
will get into why in a bit.

Hexidecimal, base 16.
0       0
1       1
2       2
3       3
4       4
5       5
6       6 
7       7
8       8   
9       9
A      10
B      11
C      12
D      13
E      14
F      15

Once you get past base 10, you need to represent numbers 10 and beyond
in a single character digit. Hence, we start using the alphabet.


Now, you remeber those 15 I showed you in Binary above?  Well,
it turns out you can convert back and forth from Hex to Binary
very simply.  4 Binary digits = 1 Hexidecimal digit and 1 Hexidecimal
digit = 4 binary digits.

From here on we will use a lowercase "b" to represent binary and a lowercase
"h" to represent hexidecimal

1111b = 0Fh = 15

0ABCh

in Binary is:

A = 1010
B = 1011
C = 1100

So,
0A     B    Ch 
1010 1011 1100b


0ABCh = 101010111100b


Group the Binary digits into 4's from right first, then left and 
you can quickly convert to base 16 without going thru base 10.

Why is this useful?  well, if you have a binary number like:

1010101101010101101010b

And you want to find out what it's base 10 number looks like, you have to

1*2^21 + 0*2^20 + 1*2^19 + 0*2^18 + 1*2^17 + 0*2^16 + 1*2^15 + 1*2^14 
+ 0*2^13 + 1*2^12 + 0*2^11 1*2^10 + 0*2^9 + 1*2^8 + 0*2^7 + 1*2^6 
+ 1*2^5 + 0*2^4 + 1*2^3 + 0*2^2 + 1*2^1 +  0*2^0

To get the answer.  Even when you eliminate the 0s
1*2^21 + 1*2^19 + 1*2^17 + 1*2^15 + 1*2^14 + 1*2^12 + 1*2^10 + 1*2^8  + 1*2^6 
+ 1*2^5 + 1*2^3  + 1*2^1

So, here is a better way

Divide into 4's from the right
10 1010 1101 0101 0110 1010b

Then convert each to Hex
2   A    D     5    6    Ah

2AD56Ah

2*16^5 + A*16^4 + D*16^3 + 5*16^2 + 6*16^1 + A*16^0  = 2807146 

A lot easier now


In general, let's say you have 2 bases, base x and base y.  You want to convert from
base x to base y.

LOG y / LOG x = Number of digits from base x that are grouped into base y.

If this does not come out even, Then you must go thru base 10 to convert,
or find a base inbetween the two that will work out evenly for them.


LOG 16 / LOG 2 = 4

LOG 2 / LOG 16 = .25

So, it may be better to put the larger base on top, so you know that
1 digit = x digits and x digits = 1 digits.

LOG 16 / LOG 2 = 4

1 base 16 Digit  = 4 Binary Digits
4 Binary Digits  = 1 base 16 Digit.


An example of a base that you would need a "middle" base to convert between:

Base 27 to Base 9

LOG 27 / LOG 9 = 1.5

Well, that is a tough conversion BUT notice this:

LOG 27 / LOG 3 = 3
LOG 9  / LOG 3 = 2

Easy! Just Take 1 base 27 number, from each digit, make 3 base 3 digits
then group the base 3 number into 2 digit pairs and make the base 9 digit.


Let's keep this simple:

837(b27)

8 = 022
3 = 010
7 = 021

022010021(b3)

Group into 2's

0 22 01 00 21
0 8  1   0  7 

08107(b9)

Let's check it out.

8*27^2 + 3* 27^1 + 7*27^0 = 5920

8*9^3 + 1*9^2 + 0*9^1 + 7*9^0 = 5920


And the conversion was done correctly, without having to convert to base 10, then
to base 9.


How to convert Base 10 to any base.


This is pretty simple.   You take the base 10 number.

Say 1230.

Now, whatever base you want, you divide that number by it.  Let's convert to base 5


1230/5 = 246 R 0

But, divide where you get a Whole number + a remainder like you would do
in elementary school, no decimal numbers.  The Remainder is actually
your number forming from right to left.

 0(b5)
 
Now, take that answer and get the next digit

246/5 = 49 R 1

10(b5)

49/5 = 9 R 4

410(b5)

9/5 = 1 R 4

4410(b5)

1/5 = 0 R 1

14410(b5)

You can quit once you get a Quotient of 0.

Since 0/5 = 0  never ending loop and
00000000000014410(b5) is 14410(b5)
just like
000000000100 is 100

Leading zeros have no value on the number.

Did this work?

14410(b5)

1*5^4 + 4*5^3 + 4*5^2 + 1*5^1 + 0*5^0 = 1230



Another Trick:
BinaryNumber Shift Left = Number*2

And since all numbers in a computer are represented in base 2,
This is a very quick way to multiply.

It is also a quick way to divide! Just shift the number right.

1110b = 14
0111b = 7

Shifting 14 to the right gets 14/2 = 7 and shifting 7 to the right gets 7*2 = 14


And, yet another trick:

The most common use of this trick used to be in the DOS days when everyone
used MODE 13h (320x200x256)  Now, If you take the Y coordinate, to get
to a line in linear space you need to  Y*320.  Well, it became known that

Y Shift left 6 + Y shift Left 8 is the same as Y*320.

2^6 + 2^8 = 320

Now, any combination like this works.

2^7 + 2^5 = 160 

Hence, Number Shift left 7 + Number Shift Left 5 = Number*160



Here's why it works:

You can multiply by any number using shifts and adds only.

Every number is a combination of powers of 2.  And As you know,
adding them up gives you the number it represents.

Here is the Formula for multiplying 2 numbers in base 2 using Shifts and adds


(NOTE: Carry is what digit fell off in the shift
 i.e.  if you shift 1001 to the right you get 0100 and 1 falls off, that's carry
       if you shift 1000 to the right you get 0100 and 0 falls off, that's carry
)


; This produces MULTNUM1 * MULTNUM2 = ANSWER

ANSWER = 0
MULTNUM1 = (Some Number)
MULTNUM2 = (Some Number)

MULTIPLY_LOOP:
  IF MULTNUM1 = 0 OR MULTNUM2 = 0 THEN EXIT
  
  SHIFT MULTNUM1 TO THE RIGHT  
  
  IF CARRY = 1 THEN
     ANSWER = ANSWER + MULTNUM2
  END IF
  
  SHIFT MULTNUM2 TO THE LEFT
  
  GOTO MULTIPLY_LOOP
EXIT:

PRINT ANSWER

You can do anything with shifts there, 8*20, etc.

Of course, more effient way would be to multiply by the smallest digit 
so it's less shifts, but that is just an example.  With that formula,
a MUL instruction is not needed, although I suggest if the processor 
you use has a multiply instruction you should most probably use it 
in most cases since it will be faster than a hudge loop, but on the
other hand, number shift left 2 is faster than number*2, so you must
use judgement for the case senario you are in.





------------------------------------------------------------------------------------------------
General Base Formulas:


* To convert any base to base 10:



ABCDEF(base)  <-- where the letters are place holders for numbers

A*base^5 + B*base^4 + C*base^3 + D*base^2 + E*base^1 + F*base^0 = base 10 number


* To convert base 10 to any base:

ABC  <-- where the letters are place holders for a base 10 number

ABC/NewBase = NewNumber, Remainder Z
NewNumber/NewBase = NewNumber, Remainder Y
NewNumber/NewBase = NewNumber, Remainder X
Until NewNumber = 0
             
and your answer is XYZ(newBase)


* To see the number of grouping digits when converting directly from one base to the next:

LOG(baseto)/LOG(basefrom) = Number of digits in Basefrom needed to represent 1 baseto digit.

(Or LN [Natural Log] or LOG(anybase)  it doesn't matter)
 
About Toby Opferman

Professional software engineer with over 15 years...

Learn more »
Codeproject Articles

Programming related articles...

Articles »
Resume

Resume »
Contact

Email: codeproject(at)opferman(dot)com