2017-08-09 69 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

相关问题