如何在装配中将两个大数相乘并打印出结果?

时间:2017-08-09 11:32:27

标签: assembly x86-16 tasm

我是汇编的新手,我一直试图创建一个程序,它将取三个数字([numR],[numG],[numB]),每个最大长度为3位数数字,然后执行公式:(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 :(得分:2)

你可能应该停下来意识到为什么那些RGB 24位颜色的使用就像一些奇怪的公式65536 * R ......

作为计算机中的每个值,颜色也以位编码。在24b RGB(32b ARGB)格式中,每个颜色通道具有8位(1字节)。 256 = 2 8 ,65536 = 2 16 (1 = 2 0 当然)。

所以你不需要增加任何东西,只需改变价值观。你需要先存储一些结果,结果至少是24位,通常使用32位,最多8位浪费为&#34;填充&#34;。

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

然后让我们说numRnumGnumB已经包含了它们的值..因为它们被定义为WORD,存储的值可能超出0-255范围,以下代码将&#34;消毒&#34;简单地截断它(即红色的值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的幂乘以(通过向右移位来进行无符号除法,有符号几乎可以工作,除了-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)