组装说明:AAA

时间:2018-08-06 14:45:21

标签: assembly x86 x86-16 bcd 80286

我正在查看伪代码:The Hidden Power of BCD Instructions。这是网站内容的摘要:

  

因此,让我们看一下AAA的功能。这是等效代码(来自Intel):

   IF ((AL AND 0FH) > 9) OR (AF = 1)
    THEN
            AL = (AL + 6) AND 0FH;
            AH = (AH + 1);
            AF = 1;
            CF = 1;
    ELSE
            AF = 0;
            CF = 0;
    FI;enter code here
  

对于像这样的典型的符合英特尔文档的用法是正确的:

    mov     al,6
    add     al,9    ;al=15=0Fh
    aaa             ;al=21=15h  =>  it's in decimal!

上面的算法似乎没有给出代码中注释的结果,因此我假设这里省略了一些步骤。注释说明如下:“ al = 21 = 15h =>十进制!”。

我对代码的解释如下:

  • 在添加指令之后,AL寄存器中存储的值为15(0Fh)。
  • 由于它大于10,所以将在该值上加上6,然后与0Fh进行AND运算,这将导致1s的值存储在AL寄存器中(“ AL =(AL + 6)AND 0FH;”)。 AL寄存器的值现在应为05h。
  • 该算法将AH寄存器加1,我认为是结转,因为我们对AL寄存器的4位进行了“与”运算(“ AH =(AH + 1);”)。

但是,在运行“ AH =(AH + 1);”行之前,没有提到存储在AH寄存器中的值。如果将其初始化为零,则仅适用于20以下的数字。现在让我们假设它已初始化为零,我希望结果存储为AH = 1和AL = 5,但注释中会显示“ ;; al = 21 = 15h =>用十进制表示!”。在执行此代码块之前和之后,似乎还有其他事情要做。

您能告诉我我在这里想念的吗?

此外,这里如何使用CF / AF标志?

  • 我了解到,从第3位开始进位时,将设置AF标志。这是否用于调整AL寄存器以使其存储为存储注释中所述的15h值?如前所述,该算法似乎建议将tens值存储在AH寄存器中,将one值存储在AL寄存器中。
  • 为什么在这里设置CF?是为了从MSB结转,但是我 在这种特殊的加法/转换过程中看不到任何残留。我希望可以在溢出等情况下进行设置。

1 个答案:

答案 0 :(得分:7)

作者对 AAA 的操作的理解似乎被误导了,他可能将其与 DAA (加法后的小数调整AL)相混淆,但使情况变得更糟多年来的英特尔文档有时不正确地是 2 3 ,从而加剧了混乱。

我不会直接回答您的问题,但我想为您提供一些背景知识,如果有适当的文档说明,您可以根据自己的问题找出答案。您在问题中引用的文档仅适用于80286之前的处理器,即使这样,它也包含有关掩盖AL 2

的低4位的错误。

在添加两个有效未打包的BCD数字(ASCII 09或0x30)之后,将使用 AAA 的原始意图(0x39)将结果转换为有效 2位BCD编号。有些人滥用了 AAA 以外的用途。不幸的是,当286宣布时,一些滥用 AAA 的代码就破裂了。

最好以这种方式定义AAA instruction 1

IF ((( AL and 0FH ) > 9 ) or (AF==1) 
    IF CPU<286 THEN 
        AL = AL+6  
    ELSE
        AX = AX+6
    ENDIF 
    AH = AH+1 
    CF = 1 
    AF = 1 
ELSE 
    CF = 0 
    AF = 0 
ENDIF 
AL = AL and 0Fh 

添加两个个位数的BCD号码时,您需要在 AAA 之前清除AH。将两个数字相加的代码如下所示:

xor ah, ah        ; Clear AH
mov al, '6'       ; AL=0x36 (0x36 = ASCII '6')
add al, '9'       ; AL=0x36+0x39 (0x39 = ASCII '9') = 0x6F
aaa               ; AH=0x01, AL=0x05 thus AX=0x0105 . AH has upper digit, AL has the lower.

由于此代码使用有效值(0x30至0x39),因此对于支持该指令的所有处理器,其工作方式均相同 1 。更普遍的是,只要在 AL 中的值为0x00到0xF9(包括0xF9),如果在处理器<286和286上运行的 AAA 的结果将相同。以后的处理器。

如果添加三个或更多BCD编号,则可以使用AH中的值来帮助保持正确的溢出结果。


AAS的类似问题(减法后ASCII调整)

AAS 指令最好以这种方式定义 1

IF ((( AL and 0FH ) > 9 ) or (AF==1) 
    IF CPU<286 THEN 
        AL = AL-6  
    ELSE
        AX = AX-6
    ENDIF 
    AH = AH-1 
    CF = 1 
    AF = 1 
ELSE 
    CF = 0 
    AF = 0 
ENDIF 
AL = AL and 0Fh 

注意:

  • 1 AAA AAS 在x86-64处理器上不可用64位代码。
  • 2 某些80386和80486文档没有明确说明 AL 的高4位始终被清除,结果是无论使用什么处理器。您从本文引用的文档在这方面也是错误的。 AAS 指令的相关问题。
  • 3 大约80286+文档不正确地指出, AAA 实际上将 AH 加1,而实际上是 AX 递增1。更多最新的Intel手册对此表示正确,但请不要提及286之前的处理器在这方面的工作方式有所不同。 AAS 指令的相关问题。