PC Tutor by Charles Petzold
PC Magazine, Vol. 6 No. 14 (August 1987)

The two assembly language mnemonics I
find most confusing are AND and OR. I
gather these two statements manipulate
data at the bit level, not the byte level. But
all the assembly language books I have
seen tell me only that these mnemonics
perform "logical" ANDs and ORs on the
operands--no great help to novices who
aren't even sure what that means.
   What do AND and OR do?
               Gerald A. Monroe
               Lakewood, Ohio

Logical operations such as AND and OR
represent the fundamental building blocks
of digital computers. To get a good feel for
what these operations are all about, let's
begin by discussing bits. A bit is the sim-
plest form of information because it can
exhibit only one of two states. You can 
think of a bit as being either Yes or No, On
or Off, True or False, 1 or 0.

   Although the subject of bits and logical
operations is sometimes approached in an
abstract mathematical manner, bits are 
very real. In the hardware of digital com-
puters, such as the PC, virtually every in-
terconnection is a "bit carrier." The
wires, the connections between chips on 
the circuit boards, the connections within
the chips themselves--all these connec-
tions carry signals in the form of a voltage.
This voltage represents a bit. In much of
the hardware of the PC, a 1 bit is rep-
resented by a 5-volt signal and a 0 bit is rep-
resented by a zero-volt signal.

   For instance, the 8088 microprocessor
chip in the PC and PC-XT has 20 pins that
are used to address the memory chips. If
you were able to "freeze" the operation of
the PC and use a voltmeter to measure the
voltages on these 20 pins, you would find 
that each pin would measure either 0 volts
(approximately) or 5 volts (approximate-
ly). From these measurements you could
then figure out the 20-bit address the 8088
was outputting to the memory chips.

   The various integrated circuit chips on
the board manipulate or process data in 
the form of bits. They receive signals from
other chips and send signals out to other
chips. Regardless of the complexity of
these chips, they all contain transistors
wired together into small fundamental
"logic gates." These gates take two input
signals (i.e., two bits) and create from 
them an output signal (another bit).

   One simple logic gate is called the OR
gate. The input to this gate consists of two
signals (call them A and B), each of which
can be either a 0 or a 1. The output is a 1 if
either A or B is 1. You can represent this
by a formula:

   A OR B

You can summarize what an OR gate does 
with a small table. This table (and the oth-
ers like it in this article) read from left to
right as follows: For line 1, if the A state is
0 and the B state is 0, then the result of A 
OR B is 0. For line 2, if the state of A is 0
and the state of B is 1, then the result of A 
OR B is 1, and so on.

    A    B    A OR B
   ---  ---  --------
    0    0       0
    0    1       1
    1    0       1
    1    1       1

   In theory, only two transistors are re-
quired to construct an OR gate. You can 
think of the transistors as switches, one for
each of the inputs. The transistors are
wired in parallel so that the output is on (a
1 bit) if either switch is turned on.

   A second simple gate is called the AND
gate. The output to this gate is a 1 only if
both inputs are 1. Here's the formula:

   A AND B

Here's the table:

    A    B    A AND B
   ---  ---  ---------
    0    0       0
    0    1       0
    1    0       0
    1    1       1

   This gate can also be constructed (in
theory) from only two transistors, where
the two transistors are wired in series.
Like switches that are wired in series, the
output will be on (a 1 bit) only if both
switches are turned on.

   Another important (although seemingly
trivial) logical operator is called NOT.
This takes one input, which I'll call A. If
A is a 0, NOT changes it to a 1. If A is a 1,
then NOT changes it to a 0:

    A    NOT A
   ---  -------
    0      1
    1      0

   Within an integrated circuit, the output
from an OR gate can be the input to a 
NOT, so they can function together as rep-
resented by this formula:

   NOT (A OR B)

This is called a NOR gate, so we can also
represent this as

   A NOR B

Here's what its table looks like:

    A    B    A NOR B
   ---  ---  ---------
    0    0       1
    0    1       0
    1    0       0
    1    1       0

The result is simply an inversion of the OR
table results--the 0's in the OR table are
1's in the NOR table, and 1's in the OR ta-
ble become 0's in the NOR table.

   Similarly, an output from an AND gate
can feed into a NOT to construct a NAND
gate. The formula


is the same as

   NOT (A AND B)

and has the following table:

    A    B    A NAND B
   ---  ---  ----------
    0    0       1
    0    1       1
    1    0       1
    1    1       0

You may start to see some relationships be-
tween all these tables. For instance, if you
turn the third column of the OR table up-
side down, it looks like the third column of
the NAND table. That leads to the conclu-
sion that

   A OR B = (NOT A) NAND (NOT B)


   A AND B = (NOT A) NOR (NOT B)

Let me stress again that these logical oper-
ations are not solely mathematical exer-
cises but actually perform vital functions in
the PC's hardware. The transistors in the
integrated circuits are wired together to 
form little logic gates. The individual logic
gates are wired together to do more-com-
plex tasks, often within the same chip.

   I want to demonstrate this real-life ap-
plicability. As you know, a computer can
add two numbers together. We take this for
granted nowadays, but once you start 
looking at the computer in terms of logic
gates, it no longer seems trivial. How can
transistors add?

   You first must wire together an OR
gate, an AND gate, and a NAND gate. You
start with two inputs and run them into
both the OR gate and the NAND gate. The
output from the OR gate and the output
from the NAND gate become the inputs to
the AND gate. The connection can be
symbolized by the formula

   (A OR B) AND (A NAND B)

This is called an "exclusive OR" gate, of-
ten abbreviated XOR. Instead of writing
out the whole expression, we can use

   A XOR B

The table summarizing the XOR gate is
shown below:

    A    B    A XOR B
   ---  ---  ---------
    0    0       0
    0    1       1
    1    0       1
    1    1       0

You'll notice that this table is similar to
that for the OR gate except that when both
A and B are 1, the result is a 0. What
makes the XOR gate interesting is that it
seems to add the two bits together.

   When you're working with a couple of 
bits, you can add the two of them together
as shown in the following examples:

    0    0    1    1
   +0   +1   +0   +1
   --   --   --   --
    0    1    1   10

In the last example, the result is two bits 
long because of a carry bit. The rightmost
digit in each example is the result of an
XOR operation. Notice also that the carry
bit is a result of an AND operation between
the two bits. Thus, we can write formulas
for the SUM bit (the rightmost digit) and
the CARRY bit as follows:

     SUM = A XOR B

We're definitely on the right track. Now 
let's take a big step and add together two
4-bit numbers. We'll use 3 and 6 as an ex=
ample. The addition (shown in both deci-
mal and binary form) is shown below:

     3     0011
   + 6   + 0110
   ---   ------
     9     1001

When we add multidigit binary numbers
together, we start from the rightmost (least
significant) pair of bits and proceed to the
left, just as we do when we add together
multidigit decimal numbers. However, we
also have to take account of the various
carry bits. When we add a pair of bits, we
also have to add in the carry bit from the
previous calculation. We'll call this the
CARRY-IN bit. The calculation may also
result in a bit to carry into the next calcula-
tion. We'll call this the CARRY-OUT bit.
The CARRY-OUT bit from one calculation 
becomes the CARRY-IN bit for the next
   Because of this carry bit, the formulas
become a little more complex:

       SUM = (A XOR B) XOR (CARRY-IN)
              AND (CARRY-IN))

Regardless of their increasing complexity,
these formulas still involve only combina-
tions of various logic gates that are built
from transistors.

To do the full addition, you start with
the rightmost pair of bits and do both cal-
culations, then proceed to the next pair of 
bits to the left. If you want to verify that
these formulas work for the calculation 
shown above, you can put together a table
that shows the bits to be added, the SUM
from each calculation, the CARRY-OUT
from the calculation, and the CARRY-IN
from the previous calculation:

   CARRY-IN:    1   1   0   0
   A:           0   0   1   1
   B:           0   1   1   0
   SUM:         1   0   0   1
   CARRY-OUT:   0   1   1   0

   Human beings may require several
minutes to plug the bits into the formulas
and determine the final result. Transistors
do it in well under a millionth of a second.
But don't feel bad. Human beings were re-
quired to "teach" the transistors how to
add in the first place.

gramming in 8086/8088 assembly lan-
guage, you can take advantage of the mi-
croprocessor's addition hardware using
the ADD, ADC (add with carry), SUB
(subtract), and SBB (subtract with bor-
row) instructions. Since everyone is famil-
iar with addition and subtraction using
numbers, these instructions present few
problems, even for beginners.

   But the operations that are more funda-
mental to the inner architecture of the
computer--the AND, OR, NOT, and XOR
instructions--have a more tenuous con-
nection with common life. You may say "I
will take my umbrella if it looks as if it's
going to rain AND I plan to be outside for a
long time." But you'd be pretty weird if
you sat down and drew up a little table of
0's and 1's to determine if an umbrella
were indeed required for your excursion.

   When you see the AND, OR, NOT, and
XOR instruction in assembly language, 
they work on 8 or 16 bits at a shot. Let's 
look at some examples using 8-bit bytes. 
I'll be showing bytes in binary notation
with a series of eight 0's and 1's. The Mac-
ro Assembler requires that a "B" follow 
such numbers.

   Here's the first example:

   MOV AL, 01100011B

The first statement moves the value
of 01100011B into register AL. The second
statement performs a NOT operation on
that register. After these two statements,
the value of AL will be 10011100B. The
NOT operator simply changes each 0 bit to
a 1 and each 1 bit to a 0.

   In these two statements, a value is
moved into register AL, and then the OR
statement performs a logical OR operation
between that byte and the byte

   MOV AL, 01100011B
   OR  AL, 00110110B

After the second statement, the contents of
the AL register will be 01110111B. Look
at each pair of bits separately. The result is
a 1 only if the bits in either the original val-
ue or the ORed value are 1. That's how we 
defined the OR logical operation earlier in
the discussion.

   These two statements do the same
thing, except that they use the AND state-

   MOV AL, 01100011B
   AND AL, 00110110B

The result in the AL register after perform-
ing the second statement is 00100010B.
Once again, the instruction ANDed each
pair of bits.
   This is the XOR:

   MOV AL, 01100011B
   XOR AL, 00110110B

The result is 01010101B. I showed above
how the XOR logical operator is used for
addition. When you use an XOR statement
in assembly language, however, it doesn't
add the two bytes together because it
doesn't take account of the carry bits.
Each pair of bits is XORed independently
of the others.

THE MASKED BIT  Assembly language
programs often use various bits within the
same byte or word to store several pieces
of data. For instance, when the PC's BIOS
stores information about the states of the
shift keys (a subject discussed in PC Tutor,
Volume 6 Number 4), it uses only one byte.
Each of the shift keys can be either up or
down, so only 1 bit is required to describe
each key. While the PC BIOS could cer-
tainly use a separate byte to store the shift
states for each key, that would be a waste of

   When working with bit-encoded data,
the use of a "bit mask" is often helpful.
This aids in determining the state of a par-
ticular bit.

   For instance, suppose you have a byte
stored in register AL and you want to de-
termine whether the third bit from the right
is a 0 or a 1. If the bit is a 0, you want to
branch off to someplace else in the pro-
gram. If the bit is a 1, you want to coninue
processing. The bit mask you would use is
00000100B. This byte has a 1 only in the
third bit position from the right. You can
use this bit mask in the following sequence
of statements:

   AND AL, 00000100B
   JZ BitIsOff

When you perform a logical AND between
the byte in AL and 00000100B, all the bits
in AL are set to 0 except the 3rd bits from
the right. The 3rd bit from the right re-
mains unaltered. The Zero Flag would be 
set (and the program would branch) only if
this bit were originally a 0.
   Using the AND statement for this job
has a little drawback, however--it de-
stroys the value of the original byte in AL.
To retain the original value of AL, you
would instead use the TEST statement

   TEST AL, 00000100B
   JZ BitIsOff

This sets the Zero Flag if the third bit in AL
is a 0 but doesn't destroy the original con-
tents of the AL register.
   You can also use logical operations to
turn individual bits on or off. For instance,
if you wanted to set the third bit in AL to 1,
you would use

   OR AL, 00000100B

All bits remain unaltered except the third
bit from the right, which becomes a 1. Sim-
ilarly, if you wanted to set the third bit to 0,
you would use

   AND AL, 11111011B

Again, all bits remain unaltered except the 
third bit from the right, which here be-
comes a 0. If you wanted to invert the state
of the third bit (turn it from a 0 to a 1 or
from a 1 to a 0), use this:

   XOR AL, 00000100B

   The ability of XOR to invert bits also
makes it useful in some graphics video ani-
mation. The first XOR draws a figure on
the display by inverting display bits. A sec-
ond XOR reinverts the display bits, effec-
tively erasing the figure and restoring the
appearance of the original display.


© Charles Petzold, 1987, code@charlespetzold.com
This page last updated September, 1999.