The Art of Assembly Language
|
2.8 Logical Operations on Binary Numbers and Bit Strings
The previous section defines the logical functions for single bit operands. Because the 80x86 uses groups of 8, 16, or 32 bits, we need to extend the definition of these functions to deal with more than 2 bits. Logical functions on the 80x86 operate on a bit-by-bit (or bitwise) basis. Given two values, these functions operate on bit zero producing bit zero of the result. They operate on bit one of the input values producing bit one of the result, and so on. For example, if you want to compute the logical AND of the following two 8-bit numbers, you would perform the logical AND operation on each column independently of the others:
%1011_0101 %1110_1110 ---------- %1010_0100
You may apply this bit-by-bit calculation to the other logical functions as well.
Because we've defined logical operations in terms of binary values, you'll find it much easier to perform logical operations on binary values than on other representations. Therefore, if you want to perform a logical operation on two hexadecimal numbers, you should convert them to binary first. This applies to most of the basic logical operations on binary numbers (e.g., AND, OR, XOR, and so on).
The ability to force bits to zero or one using the logical AND/OR operations and the ability to invert bits using the logical XOR operation is very important when working with strings of bits (e.g., binary numbers). These operations let you selectively manipulate certain bits within some bit string while leaving other bits unaffected. For example, if you have an 8-bit binary value X and you want to guarantee that bits 4..7 contain zeros, you could logically AND the value X with the binary value %0000_1111. This bitwise logical AND operation would force the H.O. 4 bits to zero and pass the L.O. 4 bits of X unchanged. Likewise, you could force the L.O. bit of X to one and invert bit number two of X by logically ORing X with %0000_0001 and logically exclusive-ORing X with %0000_0100, respectively. Using the logical AND, OR, and XOR operations to manipulate bit strings in this fashion is known as masking bit strings. We use the term "masking" because we can use certain values (one for AND, zero for OR/XOR) to "mask out" or "mask in" certain bits from the operation when forcing bits to zero, one, or their inverse.
The 80x86 CPUs support four instructions that apply these bitwise logical operations to their operands. The instructions are and, or, xor, and not. The and, or, and xor instructions use the same syntax as the add and sub instructions; that is,
and( source, dest ); or( source, dest ); xor( source, dest );
These operands have the same limitations as the add operands. Specifically, the source operand has to be a constant, memory, or register operand and the dest operand must be a memory or register operand. Also, the operands must be the same size and they cannot both be memory operands. These instructions compute the obvious bitwise logical operation via the equation:
dest = dest operator source
The 80x86 logical not instruction, because it has only a single operand, uses a slightly different syntax. This instruction takes the following form:
not( dest );
This instruction computes the following result:
dest = NOT( dest )
The dest operand (for not) must be a register or memory operand. This instruction inverts all the bits in the specified destination operand.
The program in Listing 2-5 inputs two hexadecimal values from the user and calculates their logical AND, OR, XOR, and NOT:
Listing 2-5: AND, OR, XOR, and NOT Example.
program LogicalOp; #include( "stdlib.hhf" ) begin LogicalOp; stdout.put( "Input left operand: " ); stdin.get( eax ); stdout.put( "Input right operand: " ); stdin.get( ebx ); mov( eax, ecx ); and( ebx, ecx ); stdout.put( "$", eax, " AND $", ebx, " = $", ecx, nl ); mov( eax, ecx ); or( ebx, ecx ); stdout.put( "$", eax, " OR $", ebx, " = $", ecx, nl ); mov( eax, ecx ); xor( ebx, ecx ); stdout.put( "$", eax, " XOR $", ebx, " = $", ecx, nl ); mov( eax, ecx ); not( ecx ); stdout.put( "NOT $", eax, " = $", ecx, nl ); mov( ebx, ecx ); not( ecx ); stdout.put( "NOT $", ebx, " = $", ecx, nl ); end LogicalOp;
|