2014-03-12 17 views
0

我刚刚在几天前开始学习装配,看起来我碰到了一堵坚固的墙。我有这个问题,我必须在汇编程序中接受一个整数输入(celcius)并将其转换为华氏。装配中的乘法和除法练习x8086

这里是我的代码:

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 

我用于输入15,这将导致 “;”这是ascii中的59。 我需要帮助转换ascii;到十进制,当我输入更多 比2数字它说溢出分工。我该如何解决?提前致谢!

编辑:我最近添加了转换代码。它现在有点不错,但如果我在输入输入超过“20”输出错误。我用Alden的想法(非常感谢很多人!)修改答案并单独转换并打印它。我现在仍在处理这个问题,我还在抓头哈哈。这么多错误大声笑。

再次编辑:这太奇怪了。我的程序只能转换以5结尾的数字。它只能正确转换5,15,25和35.这太奇怪了,其他所有的输出都搞乱了。有人可以告诉我为什么会发生这种情况?

回答

1

这需要比您想象的多一点工作。还有几种方法可以做到这一点。基本上你想要的是获得每个小数位的值,然后打印result + 48(48 is ascii 0)。

例如,假设您的输入是15.您要打印一个1和一个5。你可以通过15 mod 10得到5。然后将15除以10.结果是11 mod 10结果为1。您可以将这些值推入堆栈,直到您的value mod 10等于零。我对我的组装生疏,但这应该是一个功能模:

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 

我使用GCC风格主叫/被叫假设,但你可以做任何你想要的。接下来,你要与下面一个循环步骤

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代表堆栈指针。它指向存储在堆栈上的最后一个值。当push时,SP递减,并且引用的寄存器中的值为推送到SP指向的位置。 poppopSP指向堆栈的值到一个寄存器,然后增加SP。 (如果你想要加载一本杂志,你可以将子弹推入并弹出,这是一种先进后出的结构或堆栈)。

BP代表基本指针并指向一个位置,该位置标记了当前函数正在使用的堆栈的起点。例如,在modTen中,当函数被调用时,它将保存旧函数的基指针,将当前堆栈指针移动到基指针中,然后将其用作所有其他附近值的引用(如该函数的参数)。这样做的目的是当你的函数执行时,它需要堆栈空间来存储变量。当你的堆栈指针移动时,你会丢失事物所在的位置(据推测,尽管你可以用基本指针来完美地完成任务)。

当在程序集中编写代码时,将代码分解为函数并设置一些假设是很方便的,所以当其他人使用您的代码时,或者您将来再次使用它时,您将不需要重新读取你的所有代码都可以运行。大会通常很难理解,因为作者打算做什么并不明显。带有8086汇编的约定是函数的参数以相反的顺序压入堆栈。然后call用于跳转到该功能。调用将下一条指令的位置(返回地址)推入堆栈。然后被调用函数(或被调用者)通过按下它来保存前一个函数的基指针。然后它将SP复制到BP中,并使用值BP来引用变量。在使用之前,被调用者还将保存除AX以外的所有已使用的寄存器,然后将其恢复。 AX用于返回值,所以调用者必须在调用之前保存任何内容(如果要保留)。当函数执行时,你的堆栈看起来像这样。

       .... 
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 
           .... 

很明显对我来说,你是不是很熟悉的x86架构,编写x86汇编时,这是非常重要的。例如,您可能会或可能不知道x86使用段和指针寄存器来计算地址。随着你在x86汇编方面变得更加有经验,这可能会让你感觉不舒服。我强烈建议您找一本书或在线资源来详细介绍8086架构。如果你这样做,你将会做好充分的准备,让自己的颈绳长大并像1980年一样编码。

另外,如果你使用某种linux或unix环境,你已经有了最好的汇编学习资源世界可以为你服务。 使用objdump -S a.out来查看已编译可执行文件的程序集。如果你用-g编译,那么它会告诉你什么样的代码与什么汇编指令。井井有条。 (这是假设你正在使用gcc)。 `另外,我从来没有用过它,但是这个用户有一个source作为gcc编译8086兼容16位指令的补丁。

GOOD LUCK

+0

是辉煌的逻辑在那里!但我似乎无法理解如何去做。我知道你可以通过将它改为10来获得15,并获得它的余数来获得数字,然后打印它。但我无法理解如何做到这一点的方法。对不起,我真的是一个新手组装我还是不明白那些sp bp和push and pop意味着什么。现在我只是将答案分为10和得到了余数,并设法分离和打印数字..如果我输入15,结果是“;”我使用了mod和东西,并得到了“59”,这是正确的,但如果我去比20更高的错误 – user3110801