1.指令地址对齐
对于load/store指令,数据在内存中的地址应该对齐。
如果访存32位数据,内存地址应当与32位的数据对齐,也就是说,D_PC的最低两位应当为0(如果内存存数据以32 bit为单位,表示数据是4个字节对齐的);
如果访存16位数据,内存地址应当与16位的数据对齐,D_PC的最低位应当为0(表示数据是2个字节对齐的);
如果访存8位数据,因为内存的单位是一个字节,即不需要对齐。其具体在CPU设计中如何在硬件中实现见RISC-V LSU,SRAM,GPIO模块(2)D_sram模块中对地址移位的处理。
注意:RISC-V只支持小端格式(little-endian)。小端格式和大端格式的对比如图1所示。如果使用不同的端序存储同样的32位数0x0A0B0C0D,情况如图所示。
小端的最高位字节是0x0A,最低位字节是0x0D;
大端的最高位字节是0x0D,最低位字节是0x0A。
如果在用不同端序的系统中数据交流,需要确保传输的数据是以32位数为单位。如果以一个字节为单位,在不同的端序系统中交换数据,可能会出现问题,比如说这里小端的0x0A对应的地址(a 3),在大端的系统中,该地址存储的数据是0x0D。
图1 大端格式,小端格式[1]
RISC-V选择以小端格式为端序是因为其目前在商业上占主导地位。所有的X86-32系统和 Apple iOS,谷歌Android操作系统和微软Windows for ARM都是采用小端格式地址排序(低字节优先序) [2]。
2.加减法溢出处理
之前提到过的ADD,ADDI和SUB等指令在计算时可能会出现溢出的情况,一般来说,硬件设计会忽略算数溢出,所以RISC-V依赖于软件的检查。下面举例说明加法如何处理(减法与之类似):
无符号数相加溢出(假设 x6,x7 是无符号数)
ADD x5,x6,x7
BLTU x5,x6,overflow (跳转到 结果不正确的处理分支)
解释说明:x5为x6和x7的和,如果和比其中的加数还要小,这说明加法已经溢出,即可以转到处理溢出的分支,overflow
有符号数相加,已知imm为正数
ADDI x5,x6, imm(正数)
BLT x5,x6,overflow (跳转到 结果不正确的处理分支)
解释说明:无论x6是正数还是负数,它加上一个正数,得到的结果应该比它本身要大。如果对x5,x6进行有符号比较,x5小于x6,说明加法已经溢出,即可以转到处理溢出的分支,overflow
除去上面两种特殊情况,对于一般情况的加法,处理情况如下
(x7 < 0) && (x6 x7 >= x6) || (x7 >= 0) && (x6 x7 < x6)
ADD x5,x6,x7
SLTI x28,x7,0
SLT x29,x5,x6
BNE x28,x29,overflow (跳转到 结果不正确的处理分支)
解释说明:
如果x7小于0,那么x28为1,那么x6和x7的和应该是小于x6,对x5和x6进行比较,如果x5小于x6,x29为1,如果x5不小于x6,即说明溢出,此时x29为0。x28不等于x29,即可以转到不正确的处理分支
如果x7大于等于0,那么x28为0,同时x6和x7的和应该不小于x6,同样对x5和x6比较,如果x29为1,说明x5小于x6,即说明溢出,x28不等于x29,也会转到不正确的处理分支
或者可以理解为:若 (x7 < 0) && (x6 x7 >= x6) || (x7 >= 0) && (x6 x7 < x6)则为不正确的处理分支