Category : Assembly Language Source Code
Archive   : ASMTUT2.ZIP
Filename : CHAP7.DOC

 
Output of file : CHAP7.DOC contained in archive : ASMTUT2.ZIP




47

CHAPTER 7 - LOGIC


There are a number of operations which work on individual bits of
a byte or word. Before we start working on them, it is necessary
for you to learn the Intel method of numbering bits. Intel starts
with the low order bit, which is #0, and numbers to the left. If
you look at a byte:

7 6 5 4 3 2 1 0

that will be the ordering. If you look at a word:

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

that is the ordering. The overwhelming advantage of this is that
if you extend a number, the numbering system stays the same. That
means that if you take the number 45 :

7 6 5 4 3 2 1 0
0 0 1 0 1 1 0 1 (45d)

and sign extend it:

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0 0 0 1 0 1 1 0 1

each of the bits keeps its previous numbering. The same is true
for negative numbers. Here's -73:

7 6 5 4 3 2 1 0
1 0 1 1 0 1 1 1 (-73d)

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 1 1 1 1 1 1 1 1 0 1 1 0 1 1 1 (-73d)

In addition, the bit-position number denotes the power of 2 that
it represents. Bit 7 = 2 ** 7 = 128, bit 5 = 2 ** 5 = 32,
bit 0 = 2 ** 0 = 1. {1}.

Whenever a bit is mentioned by number, e.g. bit 5, this is what
is being talked about.


AND

We will use AND as the prototype. There are five different ways
you can AND two numbers:


____________________

1 I'm using the Fortran convention for showing exponents. That
is, 2 ** 7 is 2 to the 7th, 3 ** 19 is 3 to the 19th.

______________________

The PC Assembler Tutor - Copyright (C) 1989 Chuck Nelson




The PC Assembler Tutor 48
______________________

1. AND two register
2. AND a register with a variable
3 AND a variable with a register
4. AND a register with a constant
5. AND a variable with a constant

That is:

variable1 db ?
variable2 dw ?

and cl, dh
and al, variable1
and variable2, si
and dl, 0C2h
and variable1, 01001011b

You will notice that this time the constants are expressed in hex
and binary. These are the only two reasonable alternatives. These
instructions work bit by bit, and hex and binary are the only two
ways of displaying a number bitwise (bit by bit). Of course, with
hex you must still convert a hex digit into four binary digits.

The table of bitwise actions for AND is:

1 1 -> 1
1 0 -> 0
0 1 -> 0
0 0 -> 0

That is, a bit in the result will be set if and only if that bit
is set in both the source and the destination. What is this used
for? Several things. First, if you AND a register with itself,
you can check for zero.

and cx, cx

If any bit is set, then there will be a bit set in the result and
the zero flag will be cleared. If no bit is set, there will be no
bit set in the result, and the zero flag will be set. No bit will
be altered, and CX will be unchanged. This is the standard way of
checking for zero. You can't AND a variable that way:

and variable1, variable1

is an illegal instruction. But you can AND it with a constant
with all the bits set:

and variable1, 11111111b

If the bit is set in variable1, then it will be set in the
result. If it is not set in variable1, then it won't be set in
the result. This also sets the zero flag without changing the
variable.

AND is also used in masks, which will be covered at the end of
the chapter.




Chapter 7 - Logic 49
_________________


Finally, there is a variant of AND called TEST. TEST does exactly
the same thing as AND but throws away the results when it is
done. It does not change the destination. This means that it can
check for specific things without altering the data. It has the
same possibilities as AND:

variable1 db ?
variable2 dw ?

test cl, dh
test al, variable1
test variable2, si
test dl, 0C2h
test variable1, 01001011b

will set the flags exactly the same as the similar AND
instructions but will not change the destination. We need a
concrete example, and for that we'll turn to your video card. In
text mode, your screen is 80 X 25. That is 2000 cells. Each cell
has a character byte and an attribute byte. The character byte
has the actual ascii number of the character. The attribute byte
says what color the character is, what color the background is,
whether the character is high or low intensity and whether it
blinks. An attribute byte looks like this:

7 6 5 4 3 2 1 0
X R G B I R G B

Bits 0,1 and 2 are the foreground (character) color. 0 is blue, 1
is green, and 2 is red. Bits 4, 5, and 6 are the background
color. 4 is blue, 5 is green, and 6 is red. Bit 3 is high
intensity, and bit 7 is blinking. If the bit is set (1) that
particular component is activated, if the bit is cleared (0),
that component is deactivated.

The first thing to notice is how much memory we have saved by
putting all this information together. It would have been
possible to use a byte for each one of these characteristics, but
that would have required 8 X 2000 bytes = 16000 bytes. If you add
the 2000 bytes for the characters themselves, that would be 18000
bytes. As it is, we get away with 4000 bytes, a savings of over
75%. Since there are four different screens (pages) on a color
card, that is 18000 X 4 = 72000 bytes compared to 4000 X 4 =
16000. That is a huge savings.

We don't have the tools to access these bytes yet, but let's
pretend that we have moved an attribute byte into dl. We can find
out if any particular bit is set. TEST dl with a specific bit
pattern. If the zero flag is cleared, the result is not zero so
the bit was on. If the zero flag is set, the result is zero so
that bit was off


test dl, 10000000b ; is it blinking?
test dl, 00010000b ; is there blue in the background?
test dl, 00000100b ; is there red in the foreground?




The PC Assembler Tutor 50
______________________


If we look at the zero flag, this will tell us if that component
is on. It won't tell us if the background is blue, because maybe
the green or the red is on too. Remember, test alters neither the
source nor the destination. Its purpose is to set the flags, and
the results go into the Great Bit Bucket in the Sky.


OR

The table for OR is:

1 1 -> 1
1 0 -> 1
0 1 -> 1
0 0 -> 0

If either the source or the destination bit is set, then the
result bit is set. If both are zero then the result is zero.
OR is used to turn on a specific bit.

or dl, 10000000b ; turn on blinking
or dl, 00000001b ; turn on blue foreground

After this operation, those bits will be on whether or not they
were on before. It changes none of the bits where there is a 0.
They stay the same as before.


XOR

The table for XOR is:

1 1 -> 0
1 0 -> 1
0 1 -> 1
0 0 -> 0

That is, if both are on or if both are off, then the result is
zero. If only one bit is on, then the result is 1. This is used
to toggle a bit off and on.

xor dl, 10000000b ; toggle blinking
xor dl, 00000001b ; toggle blue foreground

Where there is a 1, it will reverse the setting. Where there is a
0, the setting will stay the same. This leads to one of the
favorite pieces of code for programmers.

xor ax, ax

zeros the ax register. There are three ways to zero the ax
register:

mov ax, 0
sub ax, ax
xor ax, ax




Chapter 7 - Logic 51
_________________


The first one is very clear, but slightly slower. For the second
one, if you subtract a number from itself, you always get zero.
This is slightly faster and fairly clear.{2} For the third one,
any bit that is 1 will become 0, and and bit that is 0 will stay
0. It zeros the register as a side effect of the XOR instruction.
You'll never guess which one many programmers prefer. That's
right, XOR. Many programmers prefer the third because it helps
make the code more obsure and unreadable. That gives a certain
aura of technical complexity to the code.



NEG and NOT

NOT is a logical operation and NEG is an arithmetical operation.
We'll do both here so you can see the difference. NOT toggles the
value of each individual bit:

1 -> 0
0 -> 1

NEG negates the value of the register or variable (a signed
operation). NEG performs (0 - number) so:

neg ax
neg variable1

are equivalent to (0 - AX) and (0 - variable1) respectively. NEG
sets the flags in the same way as (0 - number).

; negvsnot.asm
; compares the operations NEG and NOT
; + + + + + + + + + + + + + + + START CODE BELOW THIS LINE
mov ax_byte, 1 ; signed
mov bx_byte, 1 ; signed
mov cx_byte, 1 ; signed
mov si_byte, 3 ; binary
mov di_byte, 3 ; binary
mov bp_byte, 3 ; binary
mov dx, 0 ; not used, so clear
lea ax, ax_byte
call set_reg_style
call show_regs

outer_loop:
call get_signed ; get number
mov bx, ax ; move it to all registers
mov cx, ax
mov si, ax
mov di, ax
mov bp, ax

not bx ; NOT the second row down
____________________

2 This is one of the first instructions in the template files.




The PC Assembler Tutor 52
______________________

not di
neg cx ; NEG the third row down
neg bp

call show_regs
jmp outer_loop

; + + + + + + + + + + + + + + + END CODE ABOVE THIS LINE


This is set up so the left registers are signed and the right
registers are binary. The top registers retain the original
value, the second registers down will do NOT and the third
registers down will do NEG.

Put a number in. On the right side, you will see that NOT (in DI)
reverses the bit pattern, while on the left, NEG (in CX) negates
the number. Do a few more. This is always true. But they seem to
be related. In fact, BX will always be 1 too negative. Why?
Remember that in the introduction on numbers, when we changed
signs, we had:

negative of number = one's complement + 1

but the one's complement is exactly NEG. It switches the value of
each bit. To get the values in the third row (CX and BP), simply
add 1 to the values in the second row (BX and DI). Remember, NOT
is a logical operation, NEG is an arithmetic operation.


MASKS

To explain masks, we'll need some data, and we'll use the
attribute byte for the monitor. Here it is again:

7 6 5 4 3 2 1 0
X R G B I R G B

Bits 0,1 and 2 are the foreground (character) color. 0 is blue, 1
is green, and 2 is red. Bits 4, 5, and 6 are the background
color. 4 is blue, 5 is green, and 6 is red. Bit 3 is high
intensity, and bit 7 is blinking.

What we want to do is turn certain bits on and off without
affecting other bits. What if we want to make the background
black without changing anything else? We use and AND mask.

and video_byte, 10001111b

Bits 0, 1, 2, 3 and 7 will remain unchanged, while bits 4, 5 and
6 will be zeroed. This will make the background black. What if we
wanted to make the background blue? This is a two step process.
First we make the background black, then set the blue background
bit. This involves first the AND mask, then an OR mask.

and video_byte, 10001111b
or video_byte, 00010000b




Chapter 7 - Logic 53
_________________


The first instruction shuts off certain bits without changing
others. The second turns on certain bits without effecting
others. The binary constant that we are using is called a mask.
You may write this constant as a binary or a hex number. You
should never write it as a signed or unsigned number (unless you
are one of those people who just adores making code unreadable).

If you want to turn off certain bits in a piece of data, use an
AND mask. The bits that you want left alone should be set to 1,
the bits that you want zeroed should be set to 0. Then AND the
mask with the data.

If you want to turn on certain bits in a piece of data, use an OR
mask. The bits that you want left alone should be set to 0. The
bits that you want turned on should be set to 1. Then OR the mask
with the data.

Go back to AND and OR to make sure you believe that this is what
will happen.









































The PC Assembler Tutor 54
______________________

SUMMARY


For AND, TEST, OR, and XOR you can have the following
combinations:

1. two register
2. a register with a variable
3 a variable with a register
4. a register with a constant
5. a variable with a constant


AND is a bitwise logical operation.

1 1 -> 1
1 0 -> 0
0 1 -> 0
0 0 -> 0

TEST does the same thing as AND except that the result is
discarded. It is used for setting the flags without altering the
data.

OR is a bitwise logical operation.

1 1 -> 1
1 0 -> 1
0 1 -> 1
0 0 -> 0

XOR is a bitwise logical operation.

1 1 -> 0
1 0 -> 1
0 1 -> 1
0 0 -> 0



You can use NOT and NEG with either a register or a variable in
memory.

NOT is a bitwise logical operation

0 -> 1
1 -> 0

NEG is an arithmetic operation. NUMBER -> - NUMBER. It gives the
negative of a signed number.


MASKS

If you want to turn off certain bits of a piece of data, use
an AND mask. The bits that you want left alone should be set
to 1, the bits that you want zeroed should be set to 0. Then




Chapter 7 - Logic 55
_________________

AND the mask with the data.

If you want to turn on certain bits of a piece of data, use
an OR mask. The bits that you want left alone should be set
to 0. The bits that you want turned on should be set to 1.
Then OR the mask with the data.