组装说明: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!"。
我对代码的解读如下:
- add指令后,AL寄存器中存储的值将为15(0Fh)。
- 由于它大于 10,因此会将 6 添加到该值并与 0Fh 进行与运算,这将导致 1s 值存储在 AL 寄存器中 ("AL = (AL + 6) AND 0FH;")。 AL 寄存器的值现在应该是 05h。
- 该算法向 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 结转,但我
在这个特定的 addition/conversion 中看不到任何结转。我希望在溢出等情况下设置它。
作者对 AAA 所做的理解似乎被误导了,他可能将其与 DAA(Decimal Adjust AL after添加),但更糟糕的是,多年来英特尔文档有时不正确2 3,从而增加了混乱。
我不会直接回答您的问题,但我想为您提供一些背景知识,使您可以根据适当的文档找出自己问题的答案。您在问题中引用的文档仅适用于早于 80286 的处理器,即使那样它也包含关于掩码 AL2[=18 的低 4 位的错误=]
AAA的初衷是在加上两个有效的解包后的BCD数(ASCII 0
到 9
或 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 AAA 和 AAS 在 x86 上的 64 位代码中不可用- 64 个处理器。
- 2 一些 80386 和 80486 文档没有明确说明 AL 的高 4 位是 无论使用什么处理器,结果中总是 被清除。您从文章中引用的文档在这方面也是错误的。 AAS 指令的相关问题。
- 3 一些 80286+ 文档错误地指出 AH 由 AAA 递增 6而实际上是 AX 增加了 6。除此之外,在这两种情况下 AH 也增加了 1。最近的英特尔手册正确理解,但不要提及 286 之前的处理器在这方面的工作方式不同。 AAS 指令的相关问题。
我正在查看伪代码: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!"。
我对代码的解读如下:
- add指令后,AL寄存器中存储的值将为15(0Fh)。
- 由于它大于 10,因此会将 6 添加到该值并与 0Fh 进行与运算,这将导致 1s 值存储在 AL 寄存器中 ("AL = (AL + 6) AND 0FH;")。 AL 寄存器的值现在应该是 05h。
- 该算法向 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 结转,但我 在这个特定的 addition/conversion 中看不到任何结转。我希望在溢出等情况下设置它。
作者对 AAA 所做的理解似乎被误导了,他可能将其与 DAA(Decimal Adjust AL after添加),但更糟糕的是,多年来英特尔文档有时不正确2 3,从而增加了混乱。
我不会直接回答您的问题,但我想为您提供一些背景知识,使您可以根据适当的文档找出自己问题的答案。您在问题中引用的文档仅适用于早于 80286 的处理器,即使那样它也包含关于掩码 AL2[=18 的低 4 位的错误=]
AAA的初衷是在加上两个有效的解包后的BCD数(ASCII 0
到 9
或 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 AAA 和 AAS 在 x86 上的 64 位代码中不可用- 64 个处理器。
- 2 一些 80386 和 80486 文档没有明确说明 AL 的高 4 位是 无论使用什么处理器,结果中总是 被清除。您从文章中引用的文档在这方面也是错误的。 AAS 指令的相关问题。
- 3 一些 80286+ 文档错误地指出 AH 由 AAA 递增 6而实际上是 AX 增加了 6。除此之外,在这两种情况下 AH 也增加了 1。最近的英特尔手册正确理解,但不要提及 286 之前的处理器在这方面的工作方式不同。 AAS 指令的相关问题。