最近开始涉及AArch64汇编,我注意到它有一个专门为零分配的寄存器,而在(大多数)其他架构中,你只需要使用“xor var,var”来实现。我阅读的关于“zr”的网站将其解释为“零的参考点”,听起来很像我在直流电子学中定义地面的方式。因为ARM被业余爱好者使用,将电路中的地线与代码中的零联系起来对我来说有些合理。我知道这比我的解释复杂得多,但这个类比是安全的吗?相比其他获取“0”的方法,使用这个寄存器会产生不同的结果吗?
零寄存器xzr
或者wzr
是Aarch64 ISA中的一个巧妙设计。它的寄存器编号是31,就像堆栈指针sp
或wsp
一样。根据上下文,寄存器号31将指代其中之一。
这个巧妙的设计让Aarch64 ISA简化了其指令集。例如,cmp xn,xm
指令实际上是subs xzr,xn,xm
,即减法并丢弃结果。而mov xn,xm
只是一个orr xn,xzr,xm
,即将源与零进行按位或。寄存器31只有在有意义的情况下才被识别为堆栈指针,并且指令集被聪明地选择,以便您几乎永远不会遇到此限制。
但为什么要有一个零寄存器呢?
通常的RISC理念是避免在每个指令中访问内存,而是只允许加载/存储指令接触内存。因此,RISC架构需要大量的寄存器来减少溢出到内存的需求。
几乎所有其他RISC架构都至少有32个寄存器,因此值得为零常量专门分配一个寄存器。我们可以看到:SPARC有%g0
,MIPS有$zero
或$0
,Itanium(严格来说不是RISC而是VLIW,但仍然有大量寄存器[128])有r0
,RISC-V有x0
,SH-5有R63,Blackfin有R0
,i860有R0
,PA-RISC有R0
,ARC有%r0
,Motorola 88000有r0
,Alpha有两个独立的零寄存器:整数R31
和浮点F31
...
在PowerPC中,稍微有点偏差,其中r0
根据指令的不同可以表示GPR0或数字0。然而,PowerPC的Plan 9甚至进一步偏离,通过软件将r0
初始化为0。
mov
,而是可以使用零进行add
并将其存储在目标中。否定现在也只是从零减去。对零寄存器的写入会丢弃结果,我们也不需要单独的NOP
。ARM和英特尔i960没有零寄存器,因此它们在ISA中有显式的mov
指令。ldm
和stm
,并不是简单的指令。此外,它提供了大量的寻址模式,并使用了相对复杂的指令格式。
RISC处理器指南:面向程序员和工程师
当Arm Holdings决定Aarch64也将拥有32个寄存器时,他们肯定会做同样的事情,使指令集更加RISCy和正交。现在PC、SP...也被分开了,因此我们拥有的寄存器数量比ARM多两倍以上。将其中一个寄存器作为零寄存器是非常有意义的。ldm
/stm
,而不是寻址模式。 - Peter Cordes总之,如果您发现这个比喻对您有用,那么在自己的学习过程中使用它并不是错误的!
/dev/zero
:舍弃写入,读取为一系列无限的零字节。0
位可以存在于CPU中,无论AArch64是否有这个寄存器,它们都不会与其进行比较以确定它们是真/假。从电学上讲,逻辑1
通常是高电压,0
= 地线,所以门将它们的输入与地线进行比较,并且任何地方的所有0
位都等同于地线。(这可能是一个重要的简化,当然,在ALU内部或其他某种表示形式中,位可能被反转或不存在,仅在逻辑上存在)。xzr
传播的事实。如果忽略这一点,您可以想象一个SRAM单元的替代品,其输入被断开,输出被硬连接到零。
sp
别名;我对AArch64不是很了解。zr
总是连接到 0
(即地线)。当软件代码尝试写入 zr
寄存器时,低级硬件电路通过简单地忽略写操作而保持不变。always@(posedge clk, negedge rst_n) begin
if(~rst_n) begin // set initial value when reset released.
zr <= 32'b0;
end else if(re) begin // only respond to the read operation
zr <= 32'b0;
end
if(~rst_n) begin
在逻辑上确实不必要为nz
的初始目的。我刚意识到我不应该写出来。但是不用担心,加上if(~rst_n) begin
当然是逻辑上正确的(这是电路设计中最常见的做法)。感谢你指出这一点。 - Zhaoyang