RISC-V有32个通用寄存器,其中第1个寄存器x0硬编码为0,即读出来总是0,写进去总是被丢弃。x0为RISC-V指令集的简化可贡献不少啊。
mingdu.zheng at gmail dot com
http://blog.csdn.net/zoomdy/article/details/79343785
搞过Linux的都知道Linux有两个特殊的设备:/dev/zero
和/dev/null
。从/dev/zero
可以源源不断地读到0,往/dev/null
写的任何内容都被丢弃。如果要创建一个需要填0的文件,就从/dev/zero
拷贝,如果要丢弃一些输出,就把输出重定向到/dev/null
。
RISC-V的x0寄存器就相当于是硬件版的/dev/zero
和/dev/null
的组合体。从x0读出来的总是0,往x0写进去的总是被丢弃。所以这x0提供了两种功能,一是提供常量0,在软件编程中0可以说是最常用的常量了;二是提供一个可以丢弃结果的场所。有了这个x0,很多本来需要单独指令的操作只要更普通的指令加上x0就可以实现了。
比如nop
空指令,RISC-V没有提供nop
指令噢,RISC-V用addi x0, x0, 0
来实现空指令的,这条addi
使用x0作为目标寄存器,x0是会丢弃结果的,所以这条指令不会对程序状态产生任何影响,和空指令是完全等价的。这就不需要单独的空指令了。
比如neg
取负数指令,RISC-V用sub rd, x0, rs
来实现,x0 - rs
等价于 0 - rs
等价于 -rs
,有了x0,就可以用更普通的减法指令来实现取负数指令。
比如j
跳转指令,RISC-V没有单独的j
跳转指令,只有jal
跳转链接指令,跳转之前总是要把下一条指令的地址拷贝到寄存器,但是如果用x0作为jal的操作寄存器,即把下一条指令的地址拷贝到x0,那么效果就等价于j
跳转指令了,因为写入x0的任何值都是会被丢弃的呀。
比如beqz
等于零跳转指令等等一系列和0比较的跳转指令,程序中和0比较是相当常见的操作了,RISC-V中和0比较的指令就是普通的比较跳转指令,无非是用了x0寄存器做指令的操作数罢了。
其它还有很多这样的指令,用普通的指令加上x0做操作数,就实现了那些没有x0寄存器的处理器需要单独指令或者需要组合两条指令才能实现的操作。更多这样的指令可以参考《The RISC-V Instruction Set Manual Volume I: User-Level ISA》Chapter 20 RISC-V Assembly Programmer’s Handbook ,这个Handbook中定义了大量的伪指令,大部分伪指令都使用了x0作为操作数。