Anda di halaman 1dari 11

Ive prepared a little documentation to help those who are a bit unsure of the subject review their understanding.

There are two concepts that come together here. First, there is the representation of numerical data in binary (i. e., representing numbers using only the symbols 0 and 1.) The second concept is how such numbers are added, subtracted, multiplied, or manipulated in other ways and what the results of these manipulations might mean. Finally, we have the necessary methods for converting from human-understandable representations and those in binary.

Binary Representation of Unsigned Numbers

Anthropoocentric Numerical Representation typically means base 10 (decimal) positional notation, such as 314159 to represent the number 3 105 + 1 104 + 4 103 + 1 102 + 5 101 + 9 100 , using sign-magnitude for signed numbers. This means placing a minus sign - in front of numbers which we wish to designate as negative, as in -3. Binary Unsigned Representation means simply representing a number (which must be a non-negative number) by its base-2 representation, as in representing 710 by 1112 . Note that this is still positional notation, in that 1112 is interpreted as 1 23 + 1 22 + 1 1 (base-2 positional notation.) Binary representation is what all modern computers use. It makes it possible to manipulate numerical information with digital logic. Unfortunately, it takes a lot of bits to represent any numbers of signicant magnitude. Adding or otherwise manipulating numbers in binary involve very simple operations, but for numbers of signicant width it can be tedious and require signicant time for people to perform. In a computer, on the other hand, it costs almost nothing to increase the size of an adder. It will slightly decrease the speed of an arithmetic processor to make it do 32 bit arithmetic rather than 16 bit arithmetic. Processor operand size is determined not by the cost of the adder, but by the size of the data the processor will typically handle. A manufacturer who provides a 32-bit arithmetic capability when an 8-bit one will do is making the processor slower and more expensive than necessary. In mathematics, binary numbers can be of arbitrary size. In computers, however, binary numbers are of discrete sizes, typically a multiple of 8 bits

in length. A binary number which is limited to the smallest size, 8 bits, can only represent 256 values. In unsigned binary representations, this means we can only represent the numbers 0 through 255. Although it is in principle possible to represent any 256 numbers, we commonly only use the simplest representation for integers. Using 16 bits, we can most easily represent the numbers 0 - 65535 using binary unsigned representation. The general formula is that we can represent the numbers 0 through 2n1 using n bits. Although binary is ecient when it comes to doing arithmetic inside a computer, it is not concise. To represent n decimal digits requires roughly three times (3n) binary digits. A more accurate formula is given by d10 = d2 log1 0(2). (or d2 = d10 log2 (10). (Use this with care. It predicts a non-integer number of digits, which is hard to achieve.) For example, to represent the numbers up to 999 in binary, we would need 3.32 3, or 9.96 (almost 10) binary digits. To represent the numbers 0 through 1023 requires 10 binary digits, so we see that this is fairly accurate. Hexadecimal Representation is a compromise, where we use base 16. This is human-readable, with a little practice, and takes far less time to operate on, because it so much more concise. It has the further advantage of being particularly easy to convert to and from binary via hexadecimal. Hexadecimal numbers are composed of digits in the range [0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F]. Contrast this with the digits used in decimal: [0,1,2,3,4,5,6,7,8,9] and in binary: [0,1]. The hexadecimal digits A (representing the number 10), B (11), C (12), D (13), E (14), F (15) are added to the decimal digits 0 - 9. Positional notation is used for numbers larger than can be represented by a single digit, as in 0x3A to represent the number 3 16 + 10 1. Conversion between decimal and hexadecimal is fairly easy. Most calculators (including calculator programs on personal computers) will perform this. To nd what decimal number 0x3A represents, for example, we simply use positional notation to nd 0x3A = 3 16 + 10 1 = 58. To convert a decimal number to hexadecimal, there are several methods. The simplest is the standard method where the decimal number is divided by the new base (16) to get a quotient and remainder. The remainder is the 1s digit of the hexadecimal number, while the quotient is again divided by 16. The remainder of that step becomes the 16s digit, and this process is 2

repeated until the quotient is 0. To convert the decimal number 643 to hexadecimal, for example, we divide 643 by 16: the quotient is 40, the remainder is 3. We then divide 40 by 16 to get a quotient of 2 and a remainder of 8. Finally, we divide 2 by 16 to get a quotient of 0 (indicating that were done) and a remainder of 2. This gives us: 64310 = 28316 . Using the conventions in our class, we would write the hexadecimal value as 0x283. To check the conversion, convert back to decimal: 0x283 = 2 162 + 8 16 + 3 1 = 512 + 128 + 3 = 643. To convert from hexadecimal to binary or back, we use the fact that there is a one-to-one relationship between the 4-bit binary numbers 0000 through 1111 and the hexadecimal digits 0 - 9 and A - F. Heres a table. Memorize it. hex binary hex binary 0 0000 1 0001 2 0010 3 0011 4 0100 5 0101 6 0110 7 0111 8 1000 9 1001 A 1010 B 1011 C 1100 D 1101 E 1110 F 1111 Thus, to convert hexadecimal 0x43 into binary, we notice that this will require 8 bits (each hexadecimal character will require 4 bits) and write the binary equivalents of each hex character: 0x43 = 0b010000112 . To convert from binary to hexadecimal, we convert each 4-bit chunk of the binary number, starting from the right (prepending 0s if necessary). So 0b101101010011 would become 0b1011 0101 0011 = 0xB53. To convert from binary to decimal it is generally quicker and easier to convert from binary to hexadecimal, then hexadecimal to decimal than directly from binary to decimal. For example: 0b101101010011 = 1 + 1 2 + 0 4 + 0 8 + 1 16 + 0 32 + 1 64 + 0 128 + 1 256 + 1 512 + 0 1024 + 1 2048 = 2899 (going directly from binary to decimal.) 0b101101010011 = 0xB 53 = 11 256 + 5 16 + 3 = 2816 + 80 + 3 = 2899. Which was easier? Converting from decimal to hexadecimal is many times easier than from

decimal to binary directly. Although repeated division by 16 is the easiest to remember, it is not the quickest. The quickest is to simply learn multiples of powers of 16 and use a lookup-table and interpolation method. Suppose we have the following table: 0 16 0 1 16 16 2 16 32 3 16 48 4 16 64 5 16 80 6 16 96 7 16 112 8 16 128 9 16 144 10 16 160 11 16 176 12 16 192 13 16 208 14 16 224 15 16 240 To convert, say, 153, to hexadecimal, simply notice that 144 is the largest multiple of 16 less than 153, so we can write 153 as 9 16 + 9, or 9916 , or 0x99. To convert decimal to binary is almost as simple. Once we have the hexadecimal representation, we could simply write 153 = 0b10011001 using the rst table above.

Signed Versus Unsigned Numbers

Unfortunately, we cannot always rely on numbers being positive. Some are negative. (For the mathematically inclined, instead of positive, we really should talk about non-negative, as we dont have a problem representing 0 in any base.) Negative numbers can be represented by simply representing a negative number as a positive number with a minus sign in front of it. Recall that this was referred to as sign-magnitude representation and is the method typically used in decimal representations. For binary numbers suitable for operation upon in a computer, this doesnt work well. After trying some other methods, the modern method of using 2s complement representation for representing signed numbers has been adopted by everybody. In this method of representing numbers, non-negative numbers are represented just as before, by their binary representation. However, negative numbers are represented by the 2s complement of their magnitude.

This has its limitations. For example, suppose we are limited to 8 bits. Using unsigned representation, we can represent the numbers 0 - 255. If we use the same number of bits to represent signed numbers, this doesnt increase, magically, the number of unique numbers we can represent we can still only represent 256 numbers. In the standard 2s complement representation, the numbers we can represent are are those in the range [-128,127]. The number 0 is represented by the bit pattern 0b00000000. Non-negative numbers are represented by those bit patterns with the most-signicant bit 0, as 0b0xxxxxxx. Negative numbers, on the other hand, are represented by bit patterns with a leading 1, as 0b1xxxxxxx. Observe that there is one more negative number than positive numbers. If that bothers you, consider the following: if we have an even number of numbers we can represent (which is always the case in binary, since it involves powers of 2), then because we have to represent 0, we will end up being only able to represent an odd number of nonzero numbers, so you have your choice of either having an extra positive or an extra negative number, but you cant represent an equal number of positive and negative numbers. Unless, of course, you allow more than one representation of 0, which opens another can of worms. For example, suppose we wish to represent -35 using an 8-bit 2s complement representation. To do this, we rst represent 35 using (unsigned) binary. 35 = 32 + 3 = 2 16 + 3 so 35 = 0x23 = 0b100011. We must now take the 2s complement of this number. To take the 2s complement of a number it is necessary to know how many bits to use (8 in this case.) Extend the unsigned number to 8 bits, easily done by prepending 0s: 0b00100011. Next, ip every bit in the pattern, then add 1: 0b11011100 + 0b00000001 = 0b11011101 = 0xDD, which is the 2s complement representation (using 8 bits) of -35. Suppose we are given a bit pattern, say, 0b10110101. What number does it represent? We cannot answer without being told (or knowing) that whether the number represented is signed or unsigned, as the same bit patterns are used for both types of numbers. If the given bit pattern represents an unsigned number, it represents 0xB5 (use the table above) which we convert into decimal as 11 16 + 5 or 181. If the given bit pattern represents a signed number, and we are using 2s complement representation, then we know immediately that it represents a negative number (since the most-signicant bit is 1). That means that know that the bit pattern is the 2s complement of a number, say, N, and that the 5

bit pattern represents -N. To nd the number N we have to undo the 2s complement operation that was used on N to create the bit pattern. Luckily, this is easily accomplished because: Fact: Performing the 2s complement of a binary number twice results in the original number. This means that, to nd N if we have the 2s complement of N, we simply take the 2s complement of the 2s complement. In the case of the bit pattern above, 0b10110101, to nd N, we just take the 2s complement of the bit pattern: ip the bits and add 1. 0b01001010 + 1 = 0b01001011. Convert the last bit pattern to decimal: 0b01001011 = 0x4b = 4 16 + 11 = 75. This means that the original bit pattern, 0b10110101, represents, as a signed number, -75. Heres another Fact: When negative numbers -N are represented by the 2s complement of the magnitude of the number N, taking the negative of a number is equivalent to taking its 2s complement. Example: start with the number 0b10011001. As a signed number this represents some (as yet unknown) negative number. Take the 2s complement of the bit pattern: 0b01100111. Converting to decimal gives us the number 103. According to the fact presented above, this should represent -103. Add the binary numbers 0b10011001 and 0b01100111: 1111111 0b10011001 +0b01100111 ---------0b100000000 and you get 0b100000000 which, truncated to 8 bits, is 0. This gives us another method for nding the 2s complement of a binary (or hexadecimal) number. It works best for hexadecimal numbers. Lets start with 0xB5. To nd the 2s complement of this number, start with 0x100 (which is hexadecimal 256) and subtract 0xB5. This results in 0x4B. If you look above, you will nd that this is the correct result. Summary: Numbers can be represented in binary. Unsigned numbers can be represented by simply converting to binary. This is easiest to do 6

by converting through hexadecimal. Signed numbers can be represented in binary using 2s complement, where a negative number is represented by the 2s complement of the magnitude of the number.

Numerical Operations on Binary Operands

Addition of binary numbers is very simple, if tedious. To add two 8 bit numbers requires 8 addition operations, each possibly with a carry in and a carry out. Each bit-result will be either 0 or 1. All that it is necessary to know is that 0 + 0 + 0 = 0, 1 + 1 + 0 = 0 with a carry, 1 + 0 + 0 = 1, and 1 + 1 + 1 = 1 with a carry. Then all that is needed is patience. Adding hexadecimal is less tedious. It is done in a manner completely analogous to decimal addition. All that is needed is to know how to add two hexadecimal digits. For ordinary decimal digits, as long as the sum is less than 10, the result is the same as you learned in grade school. For the rest, heres a handy rule: To add two hexadecimal digits, convert them to decimal values, then add them, converting the result back to hexadecimal. For example, to add A and 7, make that 10 + 7 = 17, which is 16 + 1, so the sum would be 1 with a carry. D + E = 13 + 14 = 27 = 16 + 11, so the sum of D and E would be B with a carry. To subtract a binary number from another binary number is even more tedious, and we seldom do it. We can easily subtract hexadecimal numbers, such as the number 0x37 from the number 0x53: 7 from 3 is C with a borrow, 3 from 4 is 1, so the answer is 0x1C. You can check if this is right by adding 0x37 and 0x1C: C + 7 = 12 + 7 = 19 = 16 + 3, or 3 with a carry. 1 + 3 + 1 = 5. If we are called upon to subtract in binary, the best thing to do is take the 2s complement of the thing to subtract and add. Suppose we were required to subtract the binary number 0b00110111 (hex 0x37) from 0b01010011 (0x53). Take the 2s complement of 0b00110111 to get 0b11001001, and add: 1 11 0b01010011 +0b11001001 ----------0b100011100 7

or 0b0011100 (0x1C) with a carry out. What about multiplication or division? Unfortunately, multiplication of numbers poses additional problems beyond those in addition or subtraction. For one thing, if we multiply two 8-bit numbers, we should get a 16-bit number (133 times 87, to pick two numbers at random, is 11571, which cannot be expressed using 8 bits). For another, in order to get the correct answer, we need to know whether the numbers represent signed or unsigned numbers. For example, suppose we take the above two numbers, 133, and 87. In hexadecimal, these numbers are 0x85 and 0x57. As unsigned numbers, they represent no more than 133 and 87, and we know their product already, 11571. As signed numbers, however, 0x85 represents -123, and -123*87 = 10701. The hexadecimal representations of the two numbers, 11571 (0x2d33) and -10701 (0xd633) have some bits in common, (compare 0b0010110100110011 and 0b1101011000110011,) but they are not twos complements of one another. Try another example, say -33*72 = 0b1111011010111000 and 223*72 = 0b0011111010111000. Is there an obvious method for converting one result to the other? I dont see one. Division is, of course, even worse than multiplication. Summary: Using twos complement representation and simple binary arithmetic, addition and subtraction can be done without knowledge of whether the original numbers were signed or unsigned, and the correct answers obtained. Multiplication and addition remain a problem. Luckily, it is quite rare that applications require much multiplication and even rarer that division is required.

Application to the PIC18 Architecture

The way the PIC18 does arithmetic is in binary, and it is important to understand that all numerical data is implicitly represented using either binary 8

for unsigned numerical data or using 2s complement for signed numerical data. Another fact that it is important to understand is that all arithmetic is done using addition only. This means that, if subtraction is required, the number to be subtracted is passed through a 2s complement operation and then added. Only by understanding this can we easily understand how some of the condition ags in the status register work. We can either do all arithmetic in hexadecimal and infer the values that the ags receive, or we can manually perform the same operations the processor does (in binary) and set the ags. For example, suppose we have two values, 0x53 and 0x83, and the processor is called upon to add them (such as if one value is in the working register W and the other is in le register 0, and instruction addwf 0,f is executed). This is simple addition, and we can do it in hexadecimal: 0x53 +0x83 ----0xD6 Notice that there was no carry out, there was no carry from the low-order digit (3 + 3 = 6 doesnt carry), the result has the most-signicant bit set, and the result is not 0. We can therefore infer the values of the Z, C, DC, and N ags: Z = 0, C = 0, DC = 0, and N = 1. To determine if there is a signed overow, we notice that, if the original numbers represent signed data, then we added a negative value to a non-negative value. In such a case, signed overow could never occur, so OV = 0. Lets experiment and create the situation with a real PIC18F452 (OK, a simulator but its accurate!) I did that, and found 0xD6 in le register 0 after the add instruction. The bits in the status register were exactly as in the previous paragraph. We could also do the problem in binary: 11 0b01010011 +0b10000011 ----------0b11010110

We notice that there is no carry from the 3rd binary position into the 4th binary position, so DC = 0. There is no carry out, so C = 0. The mostsignicant bit of the result is 1, so N = 1, the result is not 0, so Z = 0, and the carry into the most-signicant bit position is 0, which equals the carry out, so OV = 0. To perform subtraction, say that things are set up exactly as in the previous example, but the instruction we wish to execute is subwf 0,f. We need, in this case, to know which value is in W. Lets assume it is 0x83, and that 0x53 is in le register 0. Then we would perform the operation by computing the 2s complement of 0x83, to get 0x7D, and adding it to 0x53: 1 0x53 +0x7D ----0xD0 Note that there was no carry out, but a carry from the low-order digits, the result is not 0, but is negative. We added two positive numbers and got a negative number, which indicates a signed overow, so Z = 0, C = 0, DC = 1, N = 1, and OV = 1. Running this in the simulator gives the same results. Performing the same operation with binary operations: 1111111 0b01010011 +0b01111101 ----------0b11010000 Note that theres a carry from bit position 3 to position 4, a carry from bit position 6 to bit position 7, but no carry out of bit position 8. The result is not 0, bit 7 of the result is 1, so Z = 0, N = 1, C = 0, DC = 1, and OV = 1. To take another example, recall that we did the binary form of the subtraction operation, subtracting the binary number 0b00110111 (hex 0x37) from 0b01010011 (0x53). We did this by taking the twos complement of the subtrahend and adding to the minuend: 10

1 11 0b01010011 +0b11001001 ----------0b100011100 This is precisely what the pic18f452 does when handed the problem, say, for example, if W contains 0x37, le register 0 contains 0x53, and the processor fetches and decodes the instruction subwf 0,w. After that instruction, W would contain 0x1C, and the status register would contain the following ag values: Z = 0, N = 0, OV = 0 (note that there is a carry in and a carry out in the 7th bit operation), C = 1, and DC = 0 (no carry between bit positions 3 and 4.)

11

Anda mungkin juga menyukai