Ok, so I need to finish this assignment tonight before my final, and I can't figure out where my error is.
This is 16-bit x86 assembly. It assembles fines, but during runtime I get divide overflow error, then crash.
Its just supposed to take input for 2 numbers, then find the greatest common denominator between the two.
.MODEL SMALL
.STACK 100h
.DATA
crlf db 13, 10, '$'
count db 0
printSize db 1
prompt db 'Please enter a number: ','$'
prompt2 db 'Do you want to compute more GCDs? (Y/N)', '$'
removeBits db 0Fh
mult2 db 10
ASCII1 db 5 DUP(?)
ASCII2 db 5 DUP(?)
storage db 5 DUP(?)
addBits dw 0030h
mult dw 1
binaryNum1 dw 0
binaryNum2 dw 0
greatestCommon dw ?
.CODE
MAIN PROC
mov ax, @data
mov ds, ax
call GCD
mov ax, 4c00h ;exit with error code 0
int 21h
MAIN ENDP
GETNUMBER PROC
mov si, 0 ;set pointer to 0
mov count, 0 ;reset count
WHILE1:
mov ah, 01h
int 21h ;get character input
cmp al, 0dh ;test for end of input
je CONTINUE ;if end (linefeed) goto CONTINUE
mov [bx+si], al ;move the digit to the offset of the address in bx
inc count
inc si
jmp WHILE1
CONTINUE:
mov mult, 1
mov cx, 0
dec count
mov cl, count
mov si, cx
LOOP1:
mov ax, 0
mov dx, 0
mov al, [bx+si]
AND al, removeBits ;remove ASCII bits
mul mult ;multiply by multiplier
add `dx, ax
mov ax, mult
mul mult2 ;multiply multiplier by 10
mov mult, ax
dec si
LOOP LOOP1
ret
GETNUMBER ENDP
PRINTNUMBER PROC
cmp ax, 10000 ;compare GCD to 10000
jb NOT5 ;if smaller, jump to NOT5
mov printSize, 5 ;else size = 5
NOT5:
cmp ax, 1000 ;compare GCD to 1000
jb NOT4 ;if smaller, jump to NOT4
mov printSize, 4 ;else size = 4
NOT4:
cmp ax, 100 ;compare GCD to 100
jb NOT3 ;if smaller, jump to NOT3
mov printSize, 3 ;else size = 3
NOT3:
cmp ax, 10 ;compare GCD to 10
jb CONTINUE1 ;if smaller, jump to CONTINUE1 (size will be 1)
mov printSize, 2 ;else size = 2
CONTINUE1:
mov cx, 0
mov cl, printSize
mov si, cx ;set index to size
mov storage+si, '$' ;move $ to end of string being built
dec si ;decrement index
WHILE3:
cmp ax, 10 ;compare GCD to 10
jb CONTINUE3 ;if less than 10, continue
div mult2 ;divide GCD by 10, remain in dx, quo in ax
OR dx, addBits ;append ASCII bits
mov storage+si, dl ;move the ASCII remainder to storage array
dec si ;decrement index
jmp WHILE3 ;loop
CONTINUE3:
OR ax, addBits ;append ASCII bits to final digit
mov storage+si, al ;mov final digit to storage array
LEA dx, storage ;load address of storage into dx
mov ah, 09h ;set function code
int 21h ;call interrupt to display the string
ret
PRINTNUMBER ENDP
GCD PROC
lea dx, prompt
mov ah, 09h
int 21h ;display prompt
lea bx, ASCII1 ;load ASCII1 to bx
lea ax, binaryNum1 ;load binNum1 to dx so GETNUMBER can work with them
call GETNUMBER
lea dx, crlf
mov ah, 09h
int 21h
lea dx, prompt
int 21h ;display prompt
lea bx, ASCII2 ;load ASCII2 to bx
lea dx, binaryNum2 ;load binNum2 to dx so GETNUMBER can work with them
call GETNUMBER
lea dx, crlf
mov ah, 09h
int 21h
WHILE2:
mov ax, binaryNum1
cmp ax, binaryNum2
je DISPLAY1 ;if num1 and num2 are equal, display the gcd
cmp ax, binaryNum2
ja GREATER1 ;if num1 > num2, jump to GREATER1
mov ax, binaryNum2 ;subtract num1 from num2
sub ax, binaryNum1
mov binaryNum2, ax ;put val in ax back into num2
mov greatestCommon, ax ;set value of gcd
jmp WHILE2
GREATER1:
mov ax, binaryNum1 ;subtract num2 from num1
sub ax, binaryNum2
mov binaryNum1, ax ;put val in ax back into num1
mov greatestCommon, ax ;set value of gcd
jmp WHILE2
DISPLAY1:
mov ax, greatestCommon ;move gcd into ax, so PRINTNUMBER can work with it
call PRINTNUMBER
GCD ENDP
END MAIN
Posts
See how many books I've read so far in 2010
Now, I'm reduced to using debug.exe =/
Anyway, one thing that I've found is that you don't have the "ret" at the end of your GCD procedure. Looking at the assembly output, my version of the assembler doesn't put one in automatically.
That won't solve the logic error, but it will get past the apparent crash. I think. Well, it worked on my machine. Hard to tell with assembly.
EDIT 1: It looks like you call GETNUMBER having it save the number somewhere.
lea bx, ASCII1 ;load ASCII1 to bx
lea ax, binaryNum1 ;load binNum1 to dx so GETNUMBER can work with them
call GETNUMBER
lea bx, ASCII2 ;load ASCII2 to bx
lea dx, binaryNum2 ;load binNum2 to dx so GETNUMBER can work with them
call GETNUMBER
So bx is the string buffer, and ax (or dx?) is the address to save it to. Either way, two things:
1.) Typo - lea ax, or lea dx? Your comments seem to indicate dx, so lea ax, binaryNum1 is wrong?
2.) I'm not seeing where in GETNUMBER you use the value of dx passed in to save the number.
edit 2: You've got an off by one error in GETNUMBER
You go:
mov cx, 0
dec count
mov cl, count
And then run the loop. However, loop decrements first, and only loops if the value is non-zero. So say you had two characters typed in ("95"), then count == 2. You decremented count, so it now equals 1. So you go into your loop, and it hits the
LOOP LOOP1
and decrements cx. cx is now equal to 0, so it stops looping - only after processing one character.
Another bug:
You use dx as your result, but at the start of every loop, you set it to 0. In C, this might be better written as:
int nDX;
while(someCondition)
{
nDX = 0;
...
nDX += somethingOrRather;
}
while what you really want is:
int nDX;
nDX = 0;
while(someCondition)
{
...
nDX += somethingOrRather;
}
EDIT 3: Your PRINTNUMBER has quite a few bugs... tell you what, I'll just post my version with a few comments below.
By the way, the divide overflow was caused by not clearing out the dx register prior to using the div instruction.
New question for you, regarding macros:
Thats my macro code, and it seems fine to me. I get these errors upon assemble...
**Error** lab8.asm(56) INPUT(12) Too many registers in expression
**Error** lab8.asm(57) INPUT(9) Symbol already defined elsewhere: INLOOP
**Error** lab8.asm(57) INPUT(12) Too many registers in expression
Also, googling just gives me a bunch of .ru sites, which... yea...
See how many books I've read so far in 2010
lab8.asm
exponent.asm
getnum.asm
putnum.asm
See how many books I've read so far in 2010