如何解决在手臂架构中如何针对不同条件计算标志值?
我正在研究arm体系结构中存在的指令,并且遇到了条件可执行指令(例如MOVEQ,CMPNE,MOVGT等)的概念, 我知道对于有条件的可执行指令,是否执行该指令是基于标志N(负),Z(零),C(进位)和V(溢出)做出的。
例如为了测试寄存器R1和R2中的两个值是否相等,执行以下比较指令-> CMP R1,R2,并监视标志Z得出结论,即,如果A和B相等,则Z = 1(因为AB为零),否则Z = 0。
同样,还有其他条件,并且要查找相应的标志值。 The table lists those condition code and the corresponding flags。
我的问题是如何计算这些标志?例如当条件为GE(大于或等于)时,为什么标志Z和V期望具有相同的值,即(Z = V)?
解决方法
#include <stdio.h>
int main ( void )
{
unsigned int N,C,V,Z;
unsigned int ra,rb,rc;
unsigned int rd,re;
for(ra=0;ra<8;ra++)
{
for(rb=0;rb<8;rb++)
{
rc=(ra&7)+((~rb)&7)+1;
rd=(ra&3)+((~rb)&3)+1;
rd=(rd>>2)&1;
rd^=((rc>>3)&1);
N=(rc>>2)&1;
C=(rc>>3)&1;
Z=0; if((rc&7)==0) Z=1;
V=rd;
for(re=4;re;re>>=1) if(re&ra) printf("1"); else printf("0");
printf(" - ");
for(re=4;re;re>>=1) if(re&rb) printf("1"); else printf("0");
printf(" = ");
for(re=4;re;re>>=1) if(re&rc) printf("1"); else printf("0");
printf(" N %u C %u V %u Z %u",N,Z);
if(N==V) printf(" NV"); else printf(" ");
if((C==1)&&(Z==0)) printf(" Cz");
printf("\n");
}
}
return(0);
}
3位有效的位可用于32位,99位有效的位可用于111位(通常用4位而不是3位更容易做到这一点,但这使更多的输出要处理,更多的位给您更多带正负号的符号)
001 - 000 = 001 N 0 C 1 V 0 Z 0 NV Cz
001 - 001 = 000 N 0 C 1 V 0 Z 1 NV
001 - 010 = 111 N 1 C 0 V 0 Z 0
001 - 011 = 110 N 1 C 0 V 0 Z 0
签名小于N!= V时,如果N == V,则末尾加1
因此,这些(上)是正负世界中的正数1-0大于1-1等于1-2小于1-3。当小于N不等于V时,不等于小于(大于或等于)N == V。
设置C且Z为零时,UNSIGNED较高(大于unsigned)。就是1-0例。
要理解这一点很重要,并且这不适用于所有体系结构,x86可能无法以这种方式工作。某些架构的进位被转换为借位标志以进行减法,而其他架构的执行未修改且不被视为借位标志。我在这里没有修改它,我正在做一个减法。
如果没有看到1-0的C设置案例,则表明我们需要将其转换为借位。基本上,如果将C设置为减法,则它的UNSIGNED大于或等于表中所示,或者至少是我希望读取的ARM ARM中的一个。
如果未设置if零,则表示它排除了大于等于或等于离开(无符号)的大于等于。
一些不需要太复杂的架构,例如:
UNSIGNED
a - b c set a >= b
a - b c clear a < b
b - a c set b >= a so a <= b
b - a c clear b < a so a > b
使用单进位标志和操作数顺序,您可以确定无符号大于或小于等于或不等于,则不需要z标志。
101 - 101 = 000 N 0 C 1 V 0 Z 1 NV
101 - 110 = 111 N 1 C 0 V 0 Z 0
101 - 111 = 110 N 1 C 0 V 0 Z 0
-3 - -3 = 0 NV
-3 - -2 = -1
-3 - -1 = -2
-3 is equal to -3 so NV indicates signed greater than or equal
-3 is less than -2 so N!=V
-3 is less tahn -1 so N!=V
如果您想知道其原因,那么我会让您考虑一下。我了解到,V是通过将进位与msbit的进位进行比较来计算的,如果它们不同,则将V设置为其他值。另一种从视觉上讲更有意义的方法是:如果操作数的msbit相同,而结果的msbit不同,则将V设置为其他值。
基本上,如果操作数的符号相同并且结果的符号不同,则带符号的溢出。因此,将(结果的)负号(符号)组合起来,并将其与由输入和输出的符号确定的标志进行比较,您可以开始了解它们之间的关系。例如,您可以手工处理一些4位的案例,并观察一下它的作用。
我以不同的方式多次写了这个答案,有时我弄乱了转储表的程序,所以希望这次我第一次做对了。
现在,标志规则可能会有例外,但是通常使用二进制补码。减法是根据我们在小学时学到的知识完成的:a-b = a + -b,然后在开始编程课时,我们学会了“二进制补码”(取反)您求反的数字并加一个,因此a-b = a +(〜b)+1非常适合逻辑,因为加法是通过三个输入两个输出Blob进行的,以将需要进位的一位加进来,操作数a,操作数b,执行和结果。 lsbit没有从前一个位执行,因此您对其进行硬编码。对于加法运算,您将其硬编码为0减,然后将其硬编码为1,对于减法,您将第二个操作数在加法器中反向,所有这些都非常好用。无论如何,一般理解可能会有一些例外情况
C is the carry bit,it is the carry out of the msbit
N is the msbit of the result,indicates negative if viewed as a signed number
Z is set if the result is zero,otherwise not
V is set if the carry in and carry out of msbit don't match otherwise not.
某些体系结构使用不同的字母名称。 C既执行位又执行无符号溢出。 V是有符号溢出的,有些体系结构只称其为溢出,但是它特定于程序员认为要签名的数字。当数字被认为是无符号的时,C是溢出标志。最好以签名溢出而不是溢出的方式来思考和讨论它。
如上所述,如果操作是减法,则表明某些操作发生借位(b大于a),某些体系结构会将进位求反。
与大多数其他指令集不同,ARM不会在每个小操作上都可以设置标志,您可以执行加操作而不设置标志,或者可以执行ADD操作并设置标志,因此您可以使用指令集的条件字段功能,您可以执行允许设置一个或多个标志的操作(cmp,sub,add,tst等),然后您可以拥有一系列不修改标志的指令但使用它们:
cmp r0,r1
movne r2,#1
moveq r2,#0
在其他架构中,您将需要产生带有管道副作用的分支
cmp r0,r1
beq over
mov r2,#1
b skip
over:
mov r2,#0
skip:
非常酷的功能,但没有足够的经验来使用它,他们将其放置在aarch64中。
Mips是相反的,它的兄弟姐妹是openrisc,risc-v等。与其在指令之间携带标志并不必处理管道问题,您可以执行操作并在同一指令中对其进行操作,如果相等,如果不相等,则比较并分支。这些标志的计算方法相同,只是存储方式,存储时间和使用方式不同。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。