【问题标题】:Assembly Instructions: AAA组装说明:AAA
【发布时间】:2018-08-06 14:45:20
【问题描述】:

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

那么,让我们来看看 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

对于像这样的典型英特尔文档兼容用途来说,情况确实如此:

    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 进行与运算,这将导致 1s 的值存储在 AL 寄存器中(“AL = (AL + 6) AND 0FH;”)。 AL 寄存器的值现在应该是 05h。
  • 该算法将 1 加到 AH 寄存器中,我认为这是结转,因为我们对 AL 寄存器的 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 结转的,但我 在这个特定的添加/转换中看不到任何结转。我希望在溢出等情况下设置它。

【问题讨论】:

  • 给出的解释似乎不正确。
  • 代码不正确。作者混淆了aaadaa 指令。
  • 因为选择的答案与标志无关,而且问题也不完全清楚,我建议将其作为欺骗关闭。
  • 我错过了 8 分钟前输入的投票。对不起。我想赞成这个问题。

标签: assembly x86 x86-16 bcd 80286


【解决方案1】:

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

我不会直接回答您的问题,但我想为您提供一些背景知识,让您在提供适当文档的情况下找出自己问题的答案。您在问题中引用的文档仅适用于早于 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(包括),如果在

如果添加三个或更多 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 

注意事项:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-28
    • 2011-07-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多