简体   繁体   中英

multiplication and division exercise in assembly x8086

I just started learning assembly a few days ago and it seems that i had hit a solid wall. I have this problem where in I have to make a program in assembly that accepts an integer input(celcius) and converts it into fahrenheit.

here is my code:

org 100h

jmp compare 
var1 db 0 
ans1 db ?
num1 db ? 
num2 db ?
ex1 db ?
ex2 db ?

compare:
cmp var1,0
je start
jne move

move:
mov bl,var1
mov num1,bl
jmp digits

start:


mov ah,01h
int 21h
mov num1,al
cmp num1,0dh
jne digits
je convert

digits:



mov ah,01h
int 21h
cmp al,0dh
je revert
mov num2,al
jne proceed


proceed:
sub num1,48
mov cl,num1
mov al,10
imul cl
mov num1,al

sub num2,48


mov bl,num2
add num1,bl
mov bl,num1
mov var1,bl
jmp compare

revert:
cmp num2,0 ;also added this one too recently
jne c1
sub num1,48
c1:
mov bl,num1
mov var1,bl
jmp convert



convert:



mov cl, var1
mov al, 9
imul cl
mov cl, 5
idiv cl
add al, 32
mov ans1, al                
mov bl,ans1

mov dl,0    ;i recently added this for convertion
mov al,ans1
mov bl,10
div bl
mov ex1,al
mov ex2,ah

adc ex1,48
adc ex2,48





print:
mov ah,02h
mov dl,10
int 21h
mov ah,02h
mov dl,13
int 21h

mov ah,02h
mov dl,ans1
int 21h

mov ah,02h ;print the converted values
mov dl,ex1
int 21h
mov ah,02h
mov dl,ex2
int 21h
ret

I used to input 15 which will result in ";" which is 59 in ascii. I need help in converting that ascii ; into decimal and when i input more than 2 numbers it says overflow division. How do i fix this? thanks in advance!

Edit: I recently added the conversion code. It kinda works now but if I input more than "20" in the input the output it errors. I used Alden's idea ( Thanks a lot man! ) of modding the answer and separately convert and print it. I'm still working on this right now and Im still scratching heads haha. so many errors lol.

Edit Again : this is so weird. My program can only convert numbers that end in 5. It can only convert correctly 5 , 15 , 25 and 35. That is so weird all others are messed up output. Can anybody tell me why is this happening?

This takes a little more work than you might think. There are also several ways to do this. Essentially what you want is to get the value of each decimal position and then print the result + 48 (48 is ascii 0).

For example, say that your input is 15. You want to print a 1 and a 5 . You can get the 5 by doing 15 mod 10 . Then divide the 15 by 10. This results is a 1 . 1 mod 10 results in 1 . You can push these values onto the stack until your value mod 10 is equal to zero. I am rusty on my assembly, but this should be a functional modulo:

modTen:
    push   bp
    mov    bp, sp
    push   bx
    mov    ax, word [bp+4]
    mov    bx, ax
    cwd
    idiv   10
    imul   10
    sub    bx, ax
    mov    ax, bx
    pop    bx
    mov    sp, bp
    pop    bp
    ret

I am using GCC style caller/callee assumptions, but you can do whatever you want. Next you want a loop with the following steps

push your parameter
call modTen
pop your parameter (or increment your SP)
push your result
increment a register to keep track of number of digits
divide your original value by 10
check if the result is zero. 
    If not, go back to the start of the loop. 
    If so, start popping your values and printing them.

UPDATE: SP stands for stack pointer. It points to the last value that was stored on the stack. When you push , the SP is decremented and the value in the referenced register is pushed onto the location that the SP is pointing to. pop will pop the value that SP points to off the stack into a register and then increment SP . (If you think about loading a magazine, you push bullets in, and pop them out. It is a first in, last out structure, or a stack).

BP stands for base pointer and points to a location that marks the beginning point of the stack that your current function is using. For example, in modTen , when the function is called, it saves the base pointer from the old function, moves the current stack pointer into the base pointer, and then uses that as it's reference for all other values that are near by (like the arguments for the function). The intended purpose of this is that as your function executes, it needs stack space to store variables. When your stack pointer moves around you lose the location of where things are at (supposedly, though you can make due perfectly fine with out a base pointer).

When writing in assembly, it is convenient to separate your code into functions and set some assumptions so when someone else uses your code, or you go back to reuse it in some future time, you won't need to go reread all of your code to get it to work. Assembly is often very difficult to understand because it is not obvious what the writer intended it to do. Convention with 8086 assembly is that the arguments for a function are pushed onto the stack in reverse order. Then call is used to jump to the function. Call pushes the location of the next instruction (your return address) onto the stack. Then the called function (or callee ) saves the base pointer of the previous function by pushing it. Then it copies SP into BP and the value of BP is used to reference variables. The callee will also save all used registers except for AX before using them, and then restore them afterword. AX is used for the returned value, so the caller must save whatever was in there before calling (if you want to keep it). While the function is executing your stack will look like this.

                              ....
function's second argument -> XXXX
function's first argument  -> XXXX
return address             -> XXXX
BP points here             -> XXXX
  Also, saved last BP
some variable              -> XXXX
                              ....
SP points here             -> XXXX
  and another variable
                              ....

It is apparent to me that you are not very familiar with x86 architecture, which is really important when writing x86 assembly. For example, you may or may not be aware that x86 uses segments as well as your pointer registers to calculate address. As you become more experienced in x86 assembly, this will likely trip you up. I highly recommend finding a book or online sources that give a detailed overview of the 8086 architecture. If you do so, you will be well prepared to grow out your neckbeard and hack together code like its 1980.

Also, if you are using some kind of linux or unix environment, you already have the best assembly learning sources in the world available to you. Use objdump -S a.out to view the assembly of a compiled executable. If you compile with -g then it will show you what piece of code goes with what assembly instructions. Very neat. (this is assuming you are using gcc by the way). ` Also, I have never used it, but this user has a source for a patch for gcc to compile 8086 compatible 16bit instructions.

GOOD LUCK

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM