ASCII调整和十进制调整指令如何工作?

时间:2014-06-07 00:55:06

标签: assembly x86 decimal instructions bcd

我一直在努力理解来自x86汇编语言的ASCII调整指令。

我看到整个互联网信息告诉我不同​​的事情,但我想这是以不同形式解释的同样的事情,我仍然没有。

任何人都可以解释为什么在AAA的伪代码中,AAS我们必须添加,从AL中的低位半字节中减去6?

有人可以解释AAMAAD和十进制调整指令伪代码in the Intel instruction set manuals,他们为什么会这样,他们背后的逻辑是什么?

最后,有人可以举例说明这些说明是否有用,或者至少在过去它们有用的应用程序中。

我知道现在没有使用这些说明,但我仍然想知道这些说明是如何工作的,很高兴知道。

2 个答案:

答案 0 :(得分:7)

  

为什么在AAA的伪代码中,AAS我们必须添加,从AL中的低阶半字节中减去6

因为在十六进制中每个字符有16个不同的值而BCD只有10.当你用十进制数学时,如果数字大于10,你需要取模数10并进入下一行。类似地,在BCD数学中,当加法的结果大于9时,添加6以跳过剩余的6个“无效”值并进入下一个数字。相反,你在减法中减去6。

例如:27 + 36

  27: 0010 0111
+ 36: 0011 0110
───────────────
5_13: 0101 1101 (13 >= 10)
+  6:      0110
───────────────
  63: 0110 0011 (13 + 6 = 19 = 0x13, where 0x3 is the units digit and 0x10 is the carry)

执行解压缩添加是相同的,除了您直接从单位数字到十位数,丢弃每个字节的顶部半字节

有关详细信息,请阅读


  

并且有人可以在英特尔指令集手册中解释AAM,AAD和Decimal调整指令伪代码,他们为什么这样,他们背后的逻辑是什么?

AAM只是从二进制到BCD的转换。你通常以二进制形式进行乘法,然后调用AAM将结果除以10,并将商 - 余数对存储在两个未压缩的BCD字符中

例如:

13*6 = 78 = 0100 1110
78/10 = 7 remains 8 => result = 0x78

AAD是相反的:在除法之前,你调用AAD将它从BCD转换为二进制并像其他二进制除法一样进行除法

例如:87/5

0x8*10 + 0x7 = 0x57
0x57/5 = 0x11 remains 0x7

这些指令的原因是因为在过去,记忆很昂贵,你必须尽可能减少内存使用量。因此在那个时代CISC CPU很常见。他们使用大量复杂的指令来最小化用于执行任务的指令。如今,内存便宜得多,现代架构几乎是RISCy,与CPU复杂性和代码密度相冲突

答案 1 :(得分:0)

我写了一个程序,可以帮助您理解加法后的AAA。

.model small
.data
a db '1234'
len1 db $-a
b db '9876'
len2 db $-b
result db 05 dup(?)
len3 db $-result  

.code
main proc near
mov ax,@data
mov ds,ax
                    
lea bx,a
add bl,len1
mov si,bx

lea bx,b
add bl,len2
mov di,bx

dec si
dec di
dec len3
           
lea bx,result
add bl,len3
             
mov cl,len1  
mov ax,0h

l1:                            
mov al,[si]
mov dl,[di]
cmp ah,00h
je skip 
mov ah,0h
inc al                
skip:
    add al,dl
    aaa    
    or al,30h
    mov [bx],al
    dec bx 
    dec si
    dec di
    loop l1 
cmp ah,00h
je over
mov [bx],31h
jmp finish
over:
mov [bx],30h

finish:
        
mov ax,04ch
int 21h
endp 
end

现在,正如您在程序中看到的“ add”指令之后,我们正在使用“ aaa”将数字转换为ASCII(30-39对应于0-9)。因此,编写实际输出时,我们实际上需要将其返回十六进制,以便我们得出答案的“或”。现在,使用“ si”和“ di”逐位加载数字,并检查是否存在进位,因为当我们执行“ aaa”时我们将知道,因为当数字大于9时,它将生成数字ah,因此我们将“ inc ”。请在下面查看“ aaa”的工作原理。

  AAA (ASCII Adjust after Addition)
  if low nibble of AL > 9 or AF = 1 then:
  AL = AL + 6  
  AH = AH + 1  
  AF = 1  
  CF = 1  
  else 
  AF = 0  
  CF = 0  
  in both cases: 
  clear the high nibble of AL. 

有关ASCII加,减,乘和除的更多程序,请检查此链接。 GitHub