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)