组装说明 : AAA

标签 assembly x86 x86-16 bcd 80286

我正在查看伪代码: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 => 它是十进制的!”。

我对代码的解释如下:

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

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

你能向我解释一下我在这里缺少什么吗?

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

  • 据我所知,AF 标志是在第 3 位有进位时设置的。这是否用于调整 AL 寄存器以使其存储评论中提到的 15h 值?如前所述,该算法似乎确实建议将十位值存储在 AH 寄存器中,将个位值存储在 AL 寄存器中。
  • 为什么CF设置在这里?这是为了从 MSB 结转,但我 在这个特定的添加/转换中看不到任何结转。我希望在溢出等情况下设置它。

最佳答案

看来作者对AAA所做的理解被误导了,他可能将其与DAA(加法后的十进制调整AL)混淆了,但更糟糕的是多年来,英特尔文档有时不正确23,从而增加了困惑。

我不会直接回答您的问题,但我想向您提供一些背景知识,以便您在给出适当的文档的情况下找出自己问题的答案。您在问题中引用的文档仅适用于 80286 之前的处理器,即使如此,它也包含有关 AL2

底部 4 位屏蔽的错误

AAA 的初衷是在添加两个有效未压缩的 BCD 数字(ASCII 09)后使用 或 0x30 到 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(含),如果在 <286 和 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 AAAAAS 在 x86-64 处理器上的 64 位代码中不可用。
  • 2 一些 80386 和 80486 文档没有明确说明 AL 的高 4 位在结果中始终被清除。无论使用什么处理器。您从文章中引用的文档在这方面也是错误的。与AAS指令相关的问题。
  • 3 一些 80286+ 文档错误地指出 AHAAA 增加 6,而实际上它是AX 增加了 6。除此之外,在这两种情况下 AH 也增加了 1。最近的 Intel 手册正确地说明了这一点,但不要提及 286 之前的处理器在对此。与AAS指令相关的问题。

关于组装说明 : AAA,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51710279/

相关文章:

c - 将 C 翻译为 mips 汇编

c++ - 自动对象住在哪里(附演示)

assembly - ARM 程序集 : auto-increment register on store

c++ - 堆栈上的内存分配和缓冲区溢出,x86 ISA32

assembly - A86 - 定义与前向引用冲突

assembly - LEA 指令的目的是什么?

c - 在此汇编代码中如何设置进位标志?

linux - 如何使用 VMX 暂停和恢复虚拟机

assembly - 是否有支持带偏移量的寄存器间接寻址的 CALL 指令?

assembly - 如何计算8086 ALP中字符串中元音的数量?