Chapter One Data Representation
Chapter One Data Representation
Probably the biggest stumbling block most beginners encounter when attempting to learn assembly language is the common use of the binary and hexadecimal numbering systems. Many programmers think that hexadecimal (or hex) numbers represent absolute proof that God never intended anyone to work in assembly language. While it is true that hexadecimal numbers are a little different from what you may be used to, their advantages outweigh their disadvantages by a large margin. Nevertheless, understanding these numbering systems is important because their use simplifies other complex topics including boolean algebra and logic design, signed numeric representation, character codes, and packed data.
or
100+20+3
Each digit appearing to the left of the decimal point represents a value between zero and nine times an increasing power of ten. Digits appearing to the right of the decimal point represent a
value between zero and nine times an increasing negative power of ten. For example, the value 123.456 means:
1*10**2 + 2*10**1 + 3*10**0 + 4*10**-1 + 5*10**-2 + 6*10**-3
or
100 + 20 + 3 + 0.4 + 0.05 + 0.006
To convert decimal to binary is slightly more difficult. You must find those powers of two which, when added together, produce the decimal result. The easiest method is to work from the a large power of two down to 2**0. Consider the decimal value 1359:
2**10=1024, 2**11=2048. So 1024 is the largest power of two less than 1359. Subtract 1024 from 1359 and begin the binary value on the left with a "1" digit. Binary = "1", Decimal result is 1359 - 1024 = 335. The next lower power of two (2**9= 512) is greater than the result from above, so add a "0" to the end of the binary string. Binary = "10", Decimal result is still 335. The next lower power of two is 256 (2**8). Subtract this from 335 and add a "1" digit to the end of the binary number. Binary = "101", Decimal result is 79. 128 (2**7) is greater than 79, so tack a "0" to the end of the binary string. Binary = "1010", Decimal result remains 79. The next lower power of two (2**6 = 64) is less than79, so subtract 64 and append a "1" to the end of the binary string. Binary = "10101", Decimal result is 15.
15 is less than the next power of two (2**5 = 32) so simply add a "0" to the end of the binary string. Binary = "101010", Decimal result is still 15. 16 (2**4) is greater than the remainder so far, so append a "0" to the end of the binary string. Binary = "1010100", Decimal result is 15. 2**3(eight) is less than 15, so stick another "1" digit on the end of the binary string. Binary = "10101001", Decimal result is 7. 2**2 is less than seven, so subtract four from seven and append another one to the binary string. Binary = "101010011", decimal result is 3. 2**1 is less than three, so append a one to the end of the binary string and subtract two from the decimal value. Binary = "1010100111", Decimal result is now 1. Finally, the decimal result is one, which is2**0, so add a final "1" to the end of the binary string. The final binary result is "10101001111"
Binary numbers, although they have little importance in high level languages, appear everywhere in assembly language programs.
2) Each bit to the left is given the next successive bit number. An eight-bit binary value uses bits zero through seven:
X7 X6 X5 X4 X3 X2 X1 X0
Bit zero is usually referred to as the low order ( L.O.) bit. The left-most bit is typically called the high order ( H.O.) bit. We'll refer to the intermediate bits by their respective bit numbers.
1.2.1 Bits
The smallest "unit" of data on a binary computer is a single bit. Since a single bit is capable of representing only two different values (typically zero or one) you may get the impression that there are a very small number of items you can represent with a single bit. Not true! There are an infinite number of items you can represent with a single bit. With a single bit, you can represent any two distinct items. Examples include zero or one, true or false, on or off, male or female, and right or wrong. However, you are not limited to representing binary data types (that is, those objects which have only two distinct values). You could use a single bit to represent the numbers 723 and 1,245. Or perhaps 6,254 and 5. You could also use a single bit to represent the colors red and blue. You could even represent two unrelated objects with a single bit,. For example, you could represent the color red and the number 3,256 with a single bit. You can represent any two different values with a single bit. However, you can represent only two different values with a single bit. To confuse things even more, different bits can represent different things. For example, one bit might be used to represent the values zero and one, while an adjacent bit might be used to represent the values true and false. How can you tell by looking at the bits? The answer, of course, is that you can't. But this illustrates the whole idea behind computer data structures: data is what you define it to be. If you use a bit to represent a boolean (true/false) value then that bit (by your definition) represents true or false. For the bit to have any true meaning, you must be consistent. That is, if you're using a bit to represent true or false at one point in your program, you shouldn't use the true/false value stored in that bit to represent red or blue later.
Since most items you'll be trying to model require more than two different values, single bit values aren't the most popular data type you'll use. However, since everything else consists of groups of bits, bits will play an important role in your programs. Of course, there are several data types that require two distinct values, so it would seem that bits are important by themselves. However, you will soon see that individual bits are difficult to manipulate, so we'll often use other data types to represent boolean values.
1.2.2 Nibbles
A nibble is a collection of four bits. It wouldn't be a particularly interesting data structure except for two items: BCD (binary coded decimal) numbers and hexadecimal numbers. It takes four bits to represent a single BCD or hexadecimal digit. With a nibble, we can represent up to 16 distinct values. In the case of hexadecimal numbers, the values 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, and F are represented with four bits (see "The Hexadecimal Numbering System" on page 17). BCD uses ten different digits (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) and requires four bits. In fact, any sixteen distinct values can be represented with a nibble, but hexadecimal and BCD digits are the primary items we can represent with a single nibble.
1.2.3 Bytes
Without question, the most important data structure used by the 80x86 microprocessor is the byte. A byte consists of eight bits and is the smallest addressable datum (data item) on the 80x86 microprocessor. Main memory and I/O addresses on the 80x86 are all byte addresses. This means that the smallest item that can be individually accessed by an 80x86 program is an eightbit value. To access anything smaller requires that you read the byte containing the data and mask out the unwanted bits. The bits in a byte are normally numbered from zero to seven using the convention shown below:
Bit 0 is the low order bit or least significant bit, bit 7 is the high order bit or most significant bit of the byte. We'll refer to all other bits by their number. Note that a byte also contains exactly two nibbles:
Bits 0..3 comprise the low order nibble, bits 4..7 form the high order nibble. Since a byte contains exactly two nibbles, byte values require two hexadecimal digits. Since a byte contains eight bits, it can represent 2**8, or 256, different values. Generally, we'll use a byte to represent numeric values in the range 0..255, signed numbers in the range 128..+127 (see "Signed and Unsigned Numbers" on page 23), ASCII/IBM character codes, and
other special data types requiring no more than 256 different values. Many data types have fewer than 256 items so eight bits is usually sufficient. Since the 80x86 is a byte addressable machine, it turns out to be more efficient to manipulate a whole byte than an individual bit or nibble. For this reason, most programmers use a whole byte to represent data types that require no more than 256 items, even if fewer than eight bits would suffice. For example, we'll often represent the boolean values true and false by 00000001 and 00000000 (respectively). Probably the most important use for a byte is holding a character code. Characters typed at the keyboard, displayed on the screen, and printed on the printer all have numeric values. To allow it to communicate with the rest of the world, the IBM PC uses a variant of the ASCII character set (see "The ASCII Character Set" on page 28). There are 128 defined codes in the ASCII character set. IBM uses the remaining 128 possible values for extended character codes including European characters, graphic symbols, Greek letters, and math symbols. See Appendix A for the character/code assignments.
1.2.4 Words
A word is a group of 16 bits. We'll number the bits in a word starting from zero on up to fifteen. The bit numbering appears below:
Like the byte, bit 0 is the low order bit and bit 15 is the high order bit. When referencing the other bits in a word use their bit position number. Notice that a word contains exactly two bytes. Bits 0 through 7 form the low order byte, bits 8 through 15 form the high order byte:
Naturally, a word may be further broken down into four nibbles as shown below:
Nibble zero is the low order nibble in the word and nibble three is the high order nibble of the word. The other two nibbles are "nibble one" or "nibble two". With 16 bits, you can represent 2**16 (65,536) different values. These could be the values in the range 0..65,535 (or, as is usually the case, -32,768..+32,767) or any other data type with no more
than 65,536 values. The three major uses for words are integer values, offsets, and segment values. Words can represent integer values in the range 0..65,535 or -32,768..32,767. Unsigned numeric values are represented by the binary value corresponding to the bits in the word. Signed numeric values use the two's complement form for numeric values (see "Signed and Unsigned Numbers" on page 23). Segment values, which are always 16 bits long, constitute the paragraph address of a code, data, extra, or stack segment in memory.
Naturally, this double word can be divided into a high order word and a low order word, or four different bytes, or eight different nibbles:
Double words can represent all kinds of different things. First and foremost on the list is a segmented address. Another common item represented with a double word is a 32-bit integer value (which allows unsigned numbers in the range 0..4,294,967,295 or signed numbers in the range -2,147,483,648..2,147,483,647). 32-bit floating point values also fit into a double word. Most of the time, we'll use double words to hold segmented addresses.