|
Table of Content | |
| CHAPTER
NINE: ARITHMETIC AND LOGICAL OPERATIONS (Part 8) |
|
| 9.9 -
Sample Programs 9.9.1 - Converting Arithmetic Expressions to Assembly Language 9.9.2 - Boolean Operations Example |
9.9.3 -
64-bit Integer I/O 9.9.4 - Packing and Unpacking Date Data Types |
| 9.9 Sample Programs | |
This chapter's sample programs demonstrate several important concepts including extended precision arithmetic and logical operations arithmetic expression evaluation boolean expression evaluation and packing/unpacking data.
9.9.1 Converting Arithmetic Expressions to Assembly Language
The following sample program (Pgm9_1.asm on the companion CD-ROM) provides some examples of converting arithmetic expressions into assembly language:
; Pgm9_1.ASM
;
; Several examples demonstrating how to convert various
; arithmetic expressions into assembly language.
.xlist
include stdlib.a
includelib stdlib.lib
.list
dseg segment para public 'data'
; Arbitrary variables this program uses.
u word ?
v word ?
w word ?
x word ?
y word ?
dseg ends
cseg segment para public 'code'
assume cs:cseg
ds:dseg
; GETI- Reads an integer variable from the user and returns its
; its value in the AX register.
geti textequ <call _geti>
_geti proc
push es
push di
getsm
atoi
free
pop di
pop es
ret
_geti endp
Main proc
mov ax
dseg
mov ds
ax
mov es
ax
meminit
print
byte "Abitrary expression program"
cr
lf
byte "---------------------------"
cr
lf
byte lf
byte "Enter a value for u: "
0
geti
mov u
ax
print
byte "Enter a value for v: "
0
geti
mov v
ax
print
byte "Enter a value for w: "
0
geti
mov w
ax
print
byte "Enter a non-zero value for x: "
0
geti
mov x
ax
print
byte "Enter a non-zero value for y: "
0
geti
mov y
ax
; Okay
compute Z := (X+Y)*(U+V*W)/X and print the result.
print
byte cr
lf
byte "(X+Y) * (U+V*W)/X is "
0
mov ax
v ;Compute V*W
imul w ; and then add in
add ax
u ; U.
mov bx
ax ;Save in a temp location for now.
mov ax
x ;Compute X+Y
multiply this
add ax
y ; sum by the result above
imul bx ; and then divide the whole
idiv x ; thing by X.
puti
putcr
; Compute ((X-Y*U) + (U*V) - W)/(X*Y)
print
byte "((X-Y*U) + (U*V) - W)/(X*Y) = "
0
mov ax
y ;Compute y*u first
imul u
mov dx
X ;Now compute X-Y*U
sub dx
ax
mov cx
dx ;Save in temp
mov ax
u ;Compute U*V
imul V
add cx
ax ;Compute (X-Y*U) + (U*V)
sub cx
w ;Compute ((X-Y*U) + (U*V) - W)
mov ax
x ;Compute (X*Y)
imul y
xchg ax
cx
cwd ;Compute NUMERATOR/(X*Y)
idiv cx
puti
putcr
Quit: ExitPgm ;DOS macro to quit program.
Main endp
cseg ends
sseg segment para stack 'stack'
stk byte 1024 dup ("stack ")
sseg ends
zzzzzzseg segment para public 'zzzzzz'
LastBytes byte 16 dup (?)
zzzzzzseg ends
end Main
The following sample program (Pgm9_2.asm on the companion CD-ROM) demonstrates how to manipulate boolean values in assembly language. It also provides an example of Demorgan's Theorems in operation.
; Pgm9_2.ASM
;
; This program demonstrates DeMorgan's theorems and
; various other logical computations.
.xlist
include stdlib.a
includelib stdlib.lib
.list
dseg segment para public 'data'
; Boolean input variables for the various functions
; we are going to test.
a byte 0
b byte 0
dseg ends
cseg segment para public 'code'
assume cs:cseg
ds:dseg
; Get0or1- Reads a "0" or "1" from the user and returns its
; its value in the AX register.
get0or1 textequ <call _get0or1>
_get0or1 proc
push es
push di
getsm
atoi
free
pop di
pop es
ret
_get0or1 endp
Main proc
mov ax
dseg
mov ds
ax
mov es
ax
meminit
print
byte "Demorgan's Theorems"
cr
lf
byte "-------------------"
cr
lf
byte lf
byte "According to Demorgan's theorems
all results "
byte "between the dashed lines"
cr
lf
byte "should be equal."
cr
lf
byte lf
byte "Enter a value for a: "
0
get0or1
mov a
al
print
byte "Enter a value for b: "
0
get0or1
mov b
al
print
byte "---------------------------------"
cr
lf
byte "Computing not (A and B): "
0
mov ah
0
mov al
a
and al
b
xor al
1 ;Logical NOT operation.
puti
putcr
print
byte "Computing (not A) OR (not B): "
0
mov al
a
xor al
1
mov bl
b
xor bl
1
or al
bl
puti
print
byte cr
lf
byte "---------------------------------"
cr
lf
byte "Computing (not A) OR B: "
0
mov al
a
xor al
1
or al
b
puti
print
byte cr
lf
byte "Computing not (A AND (not B)): "
0
mov al
b
xor al
1
and al
a
xor al
1
puti
print
byte cr
lf
byte "---------------------------------"
cr
lf
byte "Computing (not A) OR B: "
0
mov al
a
xor al
1
or al
b
puti
print
byte cr
lf
byte "Computing not (A AND (not B)): "
0
mov al
b
xor al
1
and al
a
xor al
1
puti
print
byte cr
lf
byte "---------------------------------"
cr
lf
byte "Computing not (A OR B): "
0
mov al
a
or al
b
xor al
1
puti
print
byte cr
lf
byte "Computing (not A) AND (not B): "
0
mov al
a
xor al
1
and bl
b
xor bl
1
and al
bl
puti
print
byte cr
lf
byte "---------------------------------"
cr
lf
byte 0
Quit: ExitPgm ;DOS macro to quit program.
Main endp
cseg ends
sseg segment para stack 'stack'
stk byte 1024 dup ("stack ")
sseg ends
zzzzzzseg segment para public 'zzzzzz'
LastBytes byte 16 dup (?)
zzzzzzseg ends
end Main
This sample program (Pgm9_3.asm on the companion CD-ROM) shows how to read and write 64-bit integers. It provides the ATOU64 and PUTU64 routines that let you convert a string of digits to a 64-bit unsigned integer and output a 64-bit unsigned integer as a decimal string to the display.
; Pgm9_3.ASM
;
; This sample program provides two procedures that read and write
; 64-bit unsigned integer values on an 80386 or later processor.
.xlist
include stdlib.a
includelib stdlib.lib
.list
.386
option segment:use16
dp textequ <dword ptr>
byp textequ <byte ptr>
dseg segment para public 'data'
; Acc64 is a 64 bit value that the ATOU64 routine uses to input
; a 64-bit value.
Acc64 qword 0
; Quotient holds the result of dividing the current PUTU value by
; ten.
Quotient qword 0
; NumOut holds the string of digits created by the PUTU64 routine.
NumOut byte 32 dup (0)
; A sample test string for the ATOI64 routine:
LongNumber byte "123456789012345678"
0
dseg ends
cseg segment para public 'code'
assume cs:cseg
ds:dseg
; ATOU64- On entry
ES:DI point at a string containing a
; sequence of digits. This routine converts that
; string to a 64-bit integer and returns that
; unsigned integer value in EDX:EAX.
;
; This routine uses the algorithm:
;
; Acc := 0
; while digits left
;
; Acc := (Acc * 10) + (Current Digit - '0')
; Move on to next digit
;
; endwhile
ATOU64 proc near
push di ;Save because we modify it.
mov dp Acc64
0 ;Initialize our accumulator.
mov dp Acc64+4
0
; While we've got some decimal digits
process the input string:
sub eax
eax ;Zero out eax's H.O. 3 bytes.
WhileDigits: mov al
es:[di]
xor al
'0' ;Translates '0'..'9' -> 0..9
cmp al
10 ; and everything else is > 9.
ja NotADigit
; Multiply Acc64 by ten. Use shifts and adds to accomplish this:
shl dp Acc64
1 ;Compute Acc64*2
rcl dp Acc64+4
1
push dp Acc64+4 ;Save Acc64*2
push dp Acc64
shl dp Acc64
1 ;Compute Acc64*4
rcl dp Acc64+4
1
shl dp Acc64
1 ;Compute Acc64*8
rcl dp Acc64+4
1
pop edx ;Compute Acc64*10 as
add dp Acc64
edx ; Acc64*2 + Acc64*8
pop edx
adc dp Acc64+4
edx
; Add in the numeric equivalent of the current digit.
; Remember
the H.O. three words of eax contain zero.
add dp Acc64
eax ;Add in this digit
inc di ;Move on to next char.
jmp WhileDigits ;Repeat for all digits.
; Okay
return the 64-bit integer value in eax.
NotADigit: mov eax
dp Acc64
mov edx
dp Acc64+4
pop di
ret
ATOU64 endp
; PUTU64- On entry
EDX:EAX contain a 64-bit unsigned value.
; Output a string of decimal digits providing the
; decimal representation of that value.
;
; This code uses the following algorithm:
;
; di := 30;
; while edx:eax <> 0 do
;
; OutputNumber[di] := digit;
; edx:eax := edx:eax div 10
; di := di - 1;
;
; endwhile
; Output digits from OutNumber[di+1]
; through OutputNumber[30]
PUTU64 proc
push es
push eax
push ecx
push edx
push di
pushf
mov di
dseg ;This is where the output
mov es
di ; string will go.
lea di
NumOut+30 ;Store characters in string
std ; backwards.
mov byp es:[di+1]
0 ;Output zero terminating byte.
; Save the value to print so we can divide it by ten using an
; extended precision division operation.
mov dp Quotient
eax
mov dp Quotient+4
edx
; Okay
begin converting the number into a string of digits.
mov ecx
10 ;Value to divide by.
DivideLoop: mov eax
dp Quotient+4 ;Do a 64-bit by
sub edx
edx ; 32-bit division
div ecx ; (see the text
mov dp Quotient+4
eax ; for details).
mov eax
dp Quotient
div ecx
mov dp Quotient
eax
; At this time edx (dl
actually) contains the remainder of the
; above division by ten
so dl is in the range 0..9. Convert
; this to an ASCII character and save it away.
mov al
dl
or al
'0'
stosb
; Now check to see if the result is zero. When it is
we can
; quit.
mov eax
dp Quotient
or eax
dp Quotient+4
jnz DivideLoop
OutputNumber: inc di
puts
popf
pop di
pop edx
pop ecx
pop eax
pop es
ret
PUTU64 endp
; The main program provides a simple test of the two routines
; above.
Main proc
mov ax
dseg
mov ds
ax
mov es
ax
meminit
lesi LongNumber
call ATOU64
call PutU64
printf
byte cr
lf
byte "%x %x %x %x"
cr
lf
0
dword Acc64+6
Acc64+4
Acc64+2
Acc64
Quit: ExitPgm ;DOS macro to quit program.
Main endp
cseg ends
sseg segment para stack 'stack'
stk byte 1024 dup ("stack ")
sseg ends
zzzzzzseg segment para public 'zzzzzz'
LastBytes byte 16 dup (?)
zzzzzzseg ends
end Main
This sample program demonstrates how to pack and unpack data using the Date data type introduced in Chapter One.
; Pgm9_4.ASM
;
; This program demonstrates how to pack and unpack
; data types. It reads in a month
day
and year value.
; It then packs these values into the format the textbook
; presents in chapter two. Finally
it unpacks this data
; and calls the stdlib DTOA routine to print it as text.
.xlist
include stdlib.a
includelib stdlib.lib
.list
dseg segment para public 'data'
Month byte ? ;Holds month value (1-12)
Day byte ? ;Holds day value (1-31)
Year byte ? ;Holds year value (80-99)
Date word ? ;Packed data goes in here.
dseg ends
cseg segment para public 'code'
assume cs:cseg
ds:dseg
; GETI- Reads an integer variable from the user and returns its
; its value in the AX register.
geti textequ <call _geti>
_geti proc
push es
push di
getsm
atoi
free
pop di
pop es
ret
_geti endp
Main proc
mov ax
dseg
mov ds
ax
mov es
ax
meminit
print
byte "Date Conversion Program"
cr
lf
byte "-----------------------"
cr
lf
byte lf
0
; Get the month value from the user.
; Do a simple check to make sure this value is in the range
; 1-12. Make the user reenter the month if it is not.
GetMonth: print
byte "Enter the month (1-12): "
0
geti
mov Month
al
cmp ax
0
je BadMonth
cmp ax
12
jbe GoodMonth
BadMonth: print
byte "Illegal month value
please re-enter"
cr
lf
0
jmp GetMonth
GoodMonth:
; Okay
read the day from the user. Again
do a simple
; check to see if the date is valid. Note that this code
; only checks to see if the day value is in the range 1-31.
; It does not check those months that have 28
29
or 30
; day months.
GetDay: print
byte "Enter the day (1-31): "
0
geti
mov Day
al
cmp ax
0
je BadDay
cmp ax
31
jbe GoodDay
BadDay: print
byte "Illegal day value
please re-enter"
cr
lf
0
jmp GetDay
GoodDay:
; Okay
get the year from the user.
; This check is slightly more sophisticated. If the user
; enters a year in the range 1980-1999
it will automatically
; convert it to 80-99. All other dates outside the range
; 80-99 are illegal.
GetYear: print
byte "Enter the year (80-99): "
0
geti
cmp ax
1980
jb TestYear
cmp ax
1999
ja BadYear
sub dx
dx ;Zero extend year to 32 bits.
mov bx
100
div bx ;Compute year mod 100.
mov ax
dx
jmp GoodYear
TestYear: cmp ax
80
jb BadYear
cmp ax
99
jbe GoodYear
BadYear: print
byte "Illegal year value. Please re-enter"
cr
lf
0
jmp GetYear
GoodYear: mov Year
al
; Okay
take these input values and pack them into the following
; 16-bit format:
;
; bit 15 8 7 0
; | | | |
; MMMMDDDD DYYYYYYY
mov ah
0
mov bh
ah
mov al
Month ;Put Month into bit positions
mov cl
4 ; 12..15
ror ax
cl
mov bl
Day ;Put Day into bit positions
mov cl
7 ; 7..11.
shl bx
cl
or ax
bx ;Create MMMMDDDD D0000000
or al
Year ;Create MMMMDDDD DYYYYYYY
mov Date
ax ;Save away packed date.
; Print out the packed date (in hex):
print
byte "Packed date = "
0
putw
putcr
; Okay
the following code demonstrates how to unpack this date
; and put it in a form the standard library's LDTOAM routine can
; use.
mov ax
Date ;First
extract Month
mov cl
4
shr ah
cl
mov dh
ah ;LDTOAM needs month in DH.
mov ax
Date ;Next get the day.
shl ax
1
and ah
11111b
mov dl
ah ;Day needs to be in DL.
mov cx
Date ;Now process the year.
and cx
7fh ;Strip all but year bits.
print
byte "Date: "
0
LDTOAM ;Convert to a string
puts
free
putcr
Quit: ExitPgm ;DOS macro to quit program.
Main endp
cseg ends
sseg segment para stack 'stack'
stk byte 1024 dup ("stack ")
sseg ends
zzzzzzseg segment para public 'zzzzzz'
LastBytes byte 16 dup (?)
zzzzzzseg ends
end Main
|
Table of Content | |
Chapter Nine: Arithmetic And Logical
Operations (Part 8)
27 SEP 1996