如何在汇编中将两个大数相乘并打印出结果?
How can I multiply two large numbers in assembly and print out the result?
我是汇编新手,我一直在尝试创建一个程序,该程序将采用三个数字([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
您可能应该停下来并了解为什么某些奇怪的公式 65536*R 会像那样使用这些 RGB 24 位颜色 ...
与计算机中的每个值一样,颜色也以位编码。在 24b RGB (32b ARGB) 格式中,每个颜色通道有 8 位(1 字节)。 256 = 28,以及 65536 = 216(当然是 1 = 20)。
因此您无需乘以任何值,只需移动值即可。你首先需要一些东西来存储结果,结果至少是 24 位,通常使用 32 位,最上面的 8 位被浪费为 "padding".
colorResult db 0, 0, 0, 0 ; B, G, R, (alfa/padding)
那么假设 numR
、numG
、numB
已经包含它们的值.. 因为它们被定义为 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 的幂(以及通过向右移动位来进行无符号除法,有符号几乎可以工作,除了 -1/2,当 SAR
移位而不是正确除法时保持 -1)。 RGB 被定义为 8 位值是多么方便……这不是巧合,这样做正是为了使用单独的值进行如此简单的操作。
相反,存在例如 16 位 RGB 5:6:5 格式,这有助于节省 video/texture 内存(每个像素仅 2 个字节),但任何颜色操作都必须做更多的移位+masking 以获得特定的通道值,或将值组合回颜色。
编辑:当然没有机会将 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)
我是汇编新手,我一直在尝试创建一个程序,该程序将采用三个数字([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
您可能应该停下来并了解为什么某些奇怪的公式 65536*R 会像那样使用这些 RGB 24 位颜色 ...
与计算机中的每个值一样,颜色也以位编码。在 24b RGB (32b ARGB) 格式中,每个颜色通道有 8 位(1 字节)。 256 = 28,以及 65536 = 216(当然是 1 = 20)。
因此您无需乘以任何值,只需移动值即可。你首先需要一些东西来存储结果,结果至少是 24 位,通常使用 32 位,最上面的 8 位被浪费为 "padding".
colorResult db 0, 0, 0, 0 ; B, G, R, (alfa/padding)
那么假设 numR
、numG
、numB
已经包含它们的值.. 因为它们被定义为 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 的幂(以及通过向右移动位来进行无符号除法,有符号几乎可以工作,除了 -1/2,当 SAR
移位而不是正确除法时保持 -1)。 RGB 被定义为 8 位值是多么方便……这不是巧合,这样做正是为了使用单独的值进行如此简单的操作。
相反,存在例如 16 位 RGB 5:6:5 格式,这有助于节省 video/texture 内存(每个像素仅 2 个字节),但任何颜色操作都必须做更多的移位+masking 以获得特定的通道值,或将值组合回颜色。
编辑:当然没有机会将 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)