组装说明:AAA

Assembly Instructions: AAA

我正在查看伪代码:The Hidden Power of BCD Instructions。以下是网站内容的片段:

So, let's take a look at what AAA does. Here is the pseudo-code equivalent (from 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

That's true for a typical Intel documentation compliant use like this one:

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

上面的算法似乎没有给出代码中注释的结果,所以我假设这里省略了一些步骤。评论声明如下:"al=21=15h => it's in decimal!"。

我对代码的解读如下:

但是,在 运行 行 "AH = (AH + 1);" 之前没有提及存储在 AH 寄存器中的值。如果它被初始化为零,它只适用于 20 以下的数字。现在假设它被初始化为零,我希望结果存储为 AH=1 和 AL=5,但评论说“;al =21=15h => 它是十进制的!”。似乎在执行此代码块之前和之后还做了其他事情。

你能给我解释一下我在这里遗漏了什么吗?

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

作者对 AAA 所做的理解似乎被误导了,他可能将其与 DAA(Decimal Adjust AL after添加),但更糟糕的是,多年来英特尔文档有时不正确2 3,从而增加了混乱。

我不会直接回答您的问题,但我想为您提供一些背景知识,使您可以根据适当的文档找出自己问题的答案。您在问题中引用的文档仅适用于早于 80286 的处理器,即使那样它也包含关于掩码 AL2[=18 的低 4 位的错误=]

AAA的初衷是在加上两个有效的解包后的BCD数(ASCII 09 或 0x30 到 0x39) 将结果转换为 有效 2 位 BCD 码。有些人滥用 AAA 超出其设计目的。不幸的是,一些滥用 AAA 的代码在 286 发布时损坏了。

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(含),AAA 的结果将与 运行 在处理器 <286 和 286 或更高版本的处理器上。

如果添加三个或更多 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 AAAAAS 在 x86 上的 64 位代码中不可用- 64 个处理器。
  • 2 一些 80386 和 80486 文档没有明确说明 AL 的高 4 位是 无论使用什么处理器,结果中总是 被清除。您从文章中引用的文档在这方面也是错误的。 AAS 指令的相关问题。
  • 3 一些 80286+ 文档错误地指出 AHAAA 递增 6而实际上是 AX 增加了 6。除此之外,在这两种情况下 AH 也增加了 1。最近的英特尔手册正确理解,但不要提及 286 之前的处理器在这方面的工作方式不同。 AAS 指令的相关问题。