2014-03-12 18 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