2017-08-09 78 views
0

我是新來的程序集,我一直在嘗試創建一個程序,每個數字最多需要3位數字([numR],[numG],[numB]),然後執行公式:(65536 * [numR] + 256 * [numG] + [numB]),最後打印出結果。如何在裝配體中乘兩個大數字打印出結果?

我已經編寫了大部分程序(我已經能夠從用戶獲得每個數字的輸入並將其存儲在上面顯示的3個變量中),但我似乎無法找到一種方法執行公式,主要是因爲在乘以大數字時,結果會在寄存器dx和ax之間分開。

我不知道怎麼會這樣的幫助,但這裏是到目前爲止我的代碼:

;------------------------------------------ 
; PURPOSE : Color Code Generator 
; SYSTEM : Turbo Assembler Ideal Mode 
; AUTHOR : Re'em Kishnevsky 
;------------------------------------------ 

    IDEAL 

    MODEL small 

    STACK 256 

    DATASEG 
    include 'start.txt' 

    count db 0 

    num db ?, ?, ? 

    numR dw ? 
    numG dw ? 
    numB dw ? 

    numFinal dd ? 

    CODESEG 
Start: 
    mov ax, @data 
    mov ds, ax 

    ;Sets text mode 
    mov ah, 0 
    mov al, 2 ; 3 
    int 10h 


    ;Sets cursor position 0,0 
    mov dh, 0 
    mov dl, 0 
    call SetCursorPosition 

    ;Prints initial message 
    mov dx, offset msg 
    mov ah, 09h 
    int 21h 

    call ReadKeyInput 

    ;Sets cursor position 0,0 
    mov dh, 0 
    mov dl, 0 
    call SetCursorPosition 

    ;Paints the screen red 
    mov bl, 01000000b 
    call PaintScreen 

    ;Prints RED message 
    mov bp, offset red 
    mov bl, 01001111b 
    mov cx, 31 
    mov dh, 10 
    mov dl, 24 
    call PrintMessage 

    ;Sets cursor position 35,12 
    mov dh, 12 
    mov dl, 35 
    call SetCursorPosition 

    mov bl, 01001111b 
    call DetermineNumber 

    cmp [count], 1 
    je R1Digit 
    cmp [count], 2 
    je R2Digit 

    dec si 
    push [si] 
    pop [numR] 
    dec si 
    mov al, 10 
    mul [byte ptr si] 
    add [numR], ax 
    dec si 
    mov al, 100 
    mul [byte ptr si] 
    add [numR], ax 
    jmp Phase_green 

R1Digit: 
    dec si 
    push [si] 
    pop [numR] 
    jmp Phase_green 
R2Digit: 
    dec si 
    push [si] 
    pop [numR] 
    dec si 
    mov al, 10 
    mul [byte ptr si] 
    add [numR], ax 

Phase_green: 
    ;Sets cursor position 0,0 
    mov dh, 0 
    mov dl, 0 
    call SetCursorPosition 

    ;Paints the screen green 
    mov bl, 00100000b 
    call PaintScreen 

    ;Prints GREEN message 
    mov bp, offset green 
    mov bl, 00101111b 
    mov cx, 33 
    mov dh, 10 
    mov dl, 24 
    call PrintMessage 

    ;Sets cursor position 35,12 
    mov dh, 12 
    mov dl, 35 
    call SetCursorPosition 
    mov [count], 0 
    mov bl, 00101111b 
    call DetermineNumber 

    cmp [count], 1 
    je G1Digit 
    cmp [count], 2 
    je G2Digit 

    dec si 
    push [si] 
    pop [numG] 
    dec si 
    mov al, 10 
    mul [byte ptr si] 
    add [numG], ax 
    dec si 
    mov al, 100 
    mul [byte ptr si] 
    add [numG], ax 
    jmp Phase_blue 

G1Digit: 
    dec si 
    push [si] 
    pop [numG] 
    jmp Phase_blue 
G2Digit: 
    dec si 
    push [si] 
    pop [numG] 
    dec si 
    mov al, 10 
    mul [byte ptr si] 
    add [numG], ax 

Phase_blue: 
    ;Sets cursor position 0,0 
    mov dh, 0 
    mov dl, 0 
    call SetCursorPosition 

    ;Paints the screen blue 
    mov bl, 00010000b 
    call PaintScreen 

    ;Prints GREEN message 
    mov bp, offset blue 
    mov bl, 00011111b 
    mov cx, 32 
    mov dh, 10 
    mov dl, 24 
    call PrintMessage 

    ;Sets cursor position 35,12 
    mov dh, 12 
    mov dl, 35 
    call SetCursorPosition 
    mov [count], 0 
    mov bl, 00011111b 
    call DetermineNumber 

    cmp [count], 1 
    je B1Digit 
    cmp [count], 2 
    je B2Digit 

    dec si 
    push [si] 
    pop [numB] 
    dec si 
    mov al, 10 
    mul [byte ptr si] 
    add [numB], ax 
    dec si 
    mov al, 100 
    mul [byte ptr si] 
    add [numB], ax 
    jmp Phase_final 

B1Digit: 
    dec si 
    push [si] 
    pop [numB] 
    jmp Phase_final 
B2Digit: 
    dec si 
    push [si] 
    pop [numB] 
    dec si 
    mov al, 10 
    mul [byte ptr si] 
    add [numB], ax 

Phase_final: 

    mov ax, 32768 ;This is where I want the formula calculation to be performed. 
    mul [numR] ;as you can see, I divided 65536 by two so it could fit in register ax 


Exit: 

    mov ax, 4C00h 
    int 21h 

;----------------------------------------- 
;DetermineNumber - Determines the number input from the user 
;----------------------------------------- 
;Input: 
;  bl <- attribute of character 
;Output: 
;  [num] <- (digit 1, digit 2, digit 3) ,Written number 
;Registers: 
;  ah, al, bh, bl, dh, dl, cx, si 
;----------------------------------------- 
Proc DetermineNumber 
    mov si, offset num 
@@Determine_number: 

call ReadKeyInput 

cmp al, 48 
je @@0 
cmp al, 49 
je @@1 
cmp al, 50 
je @@2 
cmp al, 51 
je @@3 
cmp al, 52 
je @@Mid1_4 
cmp al, 53 
je @@Mid1_5 
cmp al, 54 
je @@Mid1_6 
cmp al, 55 
je @@Mid1_7 
cmp al, 56 
je @@Mid1_8 
cmp al, 57 
je @@Mid1_9 
cmp al, 27 
je @@Mid1_ESC 
cmp al, 13 
je @@Mid1_Enter 

@@0: cmp [count], 3 
je @@Determine_number 
mov [byte ptr si], 0 
inc [count] 
inc si 
mov al, '0' 
call PrintCharacter 
jmp @@Determine_number 

@@1: cmp [count], 3 
je @@Determine_number 
mov [byte ptr si], 1 
inc [count] 
inc si 
mov al, '1' 
call PrintCharacter 
jmp @@Determine_number 

@@2: cmp [count], 3 
je @@Determine_number 
mov [byte ptr si], 2 
inc [count] 
inc si 
mov al, '2' 
call PrintCharacter 
jmp @@Determine_number 



@@3: cmp [count], 3 
je @@Determine_number 
mov [byte ptr si], 3 
inc [count] 
inc si 
mov al, '3' 
call PrintCharacter 
jmp @@Determine_number 

@@Mid1_Determine_number: jmp @@Determine_number 
@@Mid1_4: jmp @@4 
@@Mid1_5: jmp @@5 
@@Mid1_6: jmp @@6 
@@Mid1_7: jmp @@Mid2_7 
@@Mid1_8: jmp @@Mid2_8 
@@Mid1_9: jmp @@Mid2_9 
@@Mid1_ESC: jmp @@Mid2_ESC 
@@Mid1_Enter: jmp @@Mid2_Enter 

@@4: cmp [count], 3 
je @@Mid1_Determine_number 
mov [byte ptr si], 4 
inc [count] 
inc si 
mov al, '4' 
call PrintCharacter 
jmp @@Mid1_Determine_number 


@@5: cmp [count], 3 
je @@Mid1_Determine_number 
mov [byte ptr si], 5 
inc [count] 
inc si 
mov al, '5' 
call PrintCharacter 
jmp @@Mid1_Determine_number 

@@6: cmp [count], 3 
je @@Mid1_Determine_number 
mov [byte ptr si], 6 
inc [count] 
inc si 
mov al, '6' 
call PrintCharacter 
jmp @@Mid1_Determine_number 

@@Mid2_Determine_number: jmp @@Determine_number 
@@Mid2_5: jmp @@5 
@@Mid2_6: jmp @@6 
@@Mid2_7: jmp @@7 
@@Mid2_8: jmp @@8 
@@Mid2_9: jmp @@9 
@@Mid2_ESC: jmp @@ESC 
@@Mid2_Enter: jmp @@Enter 

@@7: cmp [count], 3 
je @@Mid2_Determine_number 
mov [byte ptr si], 7 
inc [count] 
inc si 
mov al, '7' 
call PrintCharacter 
jmp @@Mid2_Determine_number 

@@8: cmp [count], 3 
je @@Mid2_Determine_number 
mov [byte ptr si], 8 
inc [count] 
inc si 
mov al, '8' 
call PrintCharacter 
jmp @@Mid2_Determine_number 

@@9: cmp [count], 3 
je @@Mid2_Determine_number 
mov [byte ptr si], 9 
inc [count] 
inc si 
mov al, '9' 
call PrintCharacter 
jmp @@Mid2_Determine_number 

@@ESC: call EndProgram 

@@Enter: 
    cmp [count], 0 
    je @@Mid2_Determine_number 

ret 
ENDP DetermineNumber 
;----------------------------------------- 
;ReadKeyInput - Reads key input 
;----------------------------------------- 
;Input: 
;  Keyboard key press 
;Output: 
;  ah <- scan code, al <- ascii code 
;Registers: 
;  ah, al 
;----------------------------------------- 
Proc ReadKeyInput 
    mov ah, 00h 
    int 16h 
    ret 
ENDP ReadKeyInput 

;---------------------------------------------------------------- 
;PaintScreen - Paints the screen in a specific color 
;---------------------------------------------------------------- 
;Input: 
;  bl -> color 
;Output: 
;  Printed message 
;Registers: 
;  ah, al, bh, bl, cx 
;---------------------------------------------------------------- 
PROC PaintScreen 
    mov ah, 09h 
    mov bh, 0 ; page number 
    mov cx, 2000  ; count of characters to write 
    mov al, '' ; character to write 
    int 10h 

    ret 
ENDP PaintScreen 

;---------------------------------------------------------------- 
;PrintMessage - Prints a message 
;---------------------------------------------------------------- 
;Input: 
;  bp -> offset of message, bl -> attribute, dl -> Starting column, dh -> Starting row, cx -> length 
;Output: 
;  Printed message 
;Registers: 
;  ah, al, bh, cx, dx, es, bp 
;---------------------------------------------------------------- 
PROC PrintMessage 
    mov ah, 13h  ; video page number 
    mov bh, 0 
    mov al, 0  ; 0-3 indicating mode 
    push ds 
    pop es  ; es:bp pointer to string to be written 
    int 10h 
ret 
ENDP PrintMessage 

Proc EndProgram 
mov dh, 0 
mov dl, 0 
call SetCursorPosition 

mov bl, 0Fh 
call PaintScreen 
mov ax, 4C00h 
int 21h 
ret 
ENDP EndProgram 

;---------------------------------------------------------------- 
;SetCursorPosition - Sets Cursor Position 
;---------------------------------------------------------------- 
;Input: 
;  dl -> Column, dh -> Row 
;Output: 
;  Printed message 
;Registers: 
;  ah, bh, dh, dl 
;---------------------------------------------------------------- 
Proc SetCursorPosition 
    mov bh, 0 
    mov ah, 2h 
    int 10h 
ret 
ENDP SetCursorPosition 

Proc PrintCharacter 
    mov ah, 09h 
    mov bh, 0 ; page number 
    mov cx, 1 ; count of characters to write 
    int 10h 

    inc dl 
    call SetCursorPosition 

ret 
ENDP PrintCharacter 

    END start 

這裏是start.txt的內容:

msg db "Press any key to continue" 
red db "Please type in the value of RED" 

green  db "Please type in the value of GREEN" 

blue  db "Please type in the value of BLUE" 

final  db "Your color code is $" 

處理器:Intel 8086,彙編:TASM

+1

當紅色爲0,綠色爲1,藍色爲500時,你想要什麼結果? 756? (通常這種24位格式的r/g/b值限於8位,即僅限於0-255,不是「三位數」)。 – Ped7g

回答

2

你應該停下來認識爲什麼那些RGB24位顏色使用那樣的一些奇怪的公式65536 * R ...

作爲計算機中的每個值,顏色也是按位編碼的。在24b RGB(32b ARGB)格式中,每個顏色通道有8位(1字節)。 256 = 2 和65536 = 2 (1 = 2 當然)。

所以你不需要乘以任何東西,只需要移動值。您首先需要存儲結果,結果至少爲24位,通常使用32位,最高8位用作「填充」。

colorResult db 0, 0, 0, 0 ; B, G, R, (alfa/padding) 

然後讓我們說numRnumGnumB已經包含了他們的價值觀..因爲他們被定義爲WORD,存儲的值可以是0-255範圍之外,這下面的代碼將「sanitize方法」通過簡單截斷它(即紅色的值260將結束爲R = 4(截斷爲8位))。

mov al,BYTE PTR [numB] 
mov ah,BYTE PTR [numG] ; this is doing *256 
; because AH is 8 bits "left" to the al 
mov WORD PTR [colorResult],ax ; store first half of result 
mov al,BYTE PTR [numR] 
xor ah,ah     ; set padding/alfa to 0 
mov WORD PTR [colorResult+2],ax ; this is doing *65536 
; because that +2 is 16 bits shift, which is *65536 

完成。

爲了使移位更加明顯(如前例所示,它由字節偏移和al/ah構成隱藏),還有一個例子:在32b寄存器的保護模式下,經常需要做相反的操作,分解24b RGB值到通道:

; eax = 24b RGB (B is low 8 bits) 
mov ebx,eax 
shr ebx,8  ; ebx will be G, this is /256 
mov ecx,eax 
shr ecx,16 ; ecx will be R, this is /65536 
mov edx,eax 
shr edx,24 ; edx will be alpha, this is /16777216 (2**24) 
; eax will be B 
; all channels (eax, ebx, ecx, edx) already contain correct value in low 8 bits 
; so now all is needed to mask out any other bits left in upper parts 
movzx eax,al 
movzx ebx,bl 
movzx ecx,cl 
; edx already contains only 8 bits of alpha, SHR did clear upper 24 bits 

所以,想想值是如何編碼的計算機,並通過2的冪如何乘法可以只通過移位位向左做(和移位位權無符號divison,簽署差不多作品,除了-1/2,當SAR轉移而不是正確的劃分時,它保持-1)。而且它是多麼的方便,RGB被定義爲8位值......這不是巧合,而是完全用單獨的值來實現這種簡單的操作。相反,存在例如16位RGB 5:6:5格式,這有助於節省視頻/紋理存儲器(每像素只有2個字節),但是任何顏色處理必須進行更多的移位+掩蔽獲得特定的頻道值,或將這些值組合成彩色。


編輯:當然沒有機會適應24B到16B寄存器,所以你不能有最終的結果在ax,這就是爲什麼我的第一個示例將最終32B顏色值到內存中,而不是到寄存器。

來加載回dx:ax例如(二16B寄存器= 32B),你可以這樣做:

mov ax,[colorResult]  ; ax = B + G*256 
mov dx,[colorResult+2] ; dx = R + alfa*256 

或用80386+ CPU,你甚至可以在實模式下使用eax,所以:

mov eax,[colorResult] ; eax = B + G*256 + R*65536 + (alfa<<24) 
+0

這是一種將字節拆分爲單獨寄存器的笨拙方式。更好:'movzx edx,al' /'shr eax,8' /'movzx ecx,al'/...無論如何,因爲它被標記爲8088.但8086系統沒有24位RGB顏色,他們? :P –

+3

@PeterCordes VGA調色板模式只有6:6:6 IIRC,但作爲獨立的字節訪問,所以它是24b RGB,每個通道有2b的填充。一些SVGA卡具有完整的8:8:8色IIRC和24/32b「真彩色模式」...即使在286實模式下也可以訪問。不要低估那麼早的PC,它已經是野獸;)只是很慢的一個。 640k對每個人都足夠了。這個例子故意作爲移動和掩蔽的例子而笨拙。標籤8088是OP沒有引起足夠重視(或缺乏OCD)的另一個例子,如文本中它是8086;):) – Ped7g

+0

非常感謝您的幫助,我是新來的換班命令,所以我有一個很難理解你的例子。與此說,我明白,你可以很容易乘以2的冪數左移,所以我想我會創建一個四字變量來存儲結果和工作在該變量,我試圖做第一次計算(R * 65536)通過將[numR]的值放入qw變量中,並將其向左移動16次,但彙編程序不會讓我這樣做。我怎麼解決這個問題? 這裏是代碼: push [numR] pop [word ptr結果] shl [結果],15 – Stonewow