装配说明:AAA

sup*_*ods 5 x86 assembly bcd x86-16 80286

我正在看伪代码:BCD指令的隐藏能力.以下是该网站内容的片段:

那么,让我们来看看AAA的作用.这是伪代码等价物(来自英特尔):

   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
Run Code Online (Sandbox Code Playgroud)

对于像这样的典型英特尔文档兼容用途,这是正确的:

    mov     al,6
    add     al,9    ;al=15=0Fh
    aaa             ;al=21=15h  =>  it's in decimal!
Run Code Online (Sandbox Code Playgroud)

上面的算法似乎没有在代码中给出结果,所以我假设这里省略了一些步骤.评论说明如下:"al = 21 = 15h =>它是十进制的!".

我对代码的解释如下:

  • 在add指令之后,存储在AL寄存器中的值将为15(0Fh).
  • 由于它大于10,因此将向该值添加6,并且使用0Fh进行AND运算,这将导致1s值存储在AL寄存器中("AL =(AL + 6)AND 0FH;").AL寄存器的值现在应为05h.
  • 算法在AH寄存器中加一个,我假设是寄存器,因为我们对AL寄存器进行了ANDed和归零4位("AH =(AH + 1);").

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

你能解释一下我在这里失踪了吗?

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

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

Mic*_*tch 7

看起来作者对AAA所做的事情的理解是错误的,他可能将其与DAA混淆(加法后的十进制调整AL),但更糟糕的是,多年来英特尔文档有时不正确2 3,因此增加了困惑.

我不打算直接回答你的问题,但我想给你一些背景信息,可以让你在给出适当的文件的情况下找出你自己问题的答案.您在问题中引用的文档仅适用于早于80286的处理器,即使这样,它也包含有关屏蔽AL 2底部4位的错误

在添加两个有效的解压缩BCD编号(ASCII 到或0x30到0x39)之后,将使用AAA的原始意图,将结果转换为有效的 2位BCD编号.有些人在设计之外滥用AAA.不幸的是,当286宣布时,一些滥用AAA的代码破了.09

该AAA指令最好的定义是这样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 
Run Code Online (Sandbox Code Playgroud)

添加两个单位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.
Run Code Online (Sandbox Code Playgroud)

由于此代码使用有效值(0x30至0x39),因此对于支持该指令的所有处理器,它将以相同的方式工作1.更一般地说,只要AL中的值是0x00到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 
Run Code Online (Sandbox Code Playgroud)

笔记:

  • 在x86-64处理器上,64位代码中没有1 AAA和AAS.
  • 2某些80386和80486文档没有说清楚AL的高4位总是在结果中被清除,无论使用什么处理器.您在文章中引用的文档在这方面也是错误的.AAS指令的相关问题.
  • 3有些80286+文档不正确地说AH通过AAA增加1,而事实上它是AX增加1.更近的英特尔手册得到了这一点,但是没有提到286之前的处理器在这方面的工作方式不同.AAS指令的相关问题.