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)