乘法和除法指令
前面了解过 RV32I不带乘除。扩展的RV32M里面有。
mul 较简单。div 是商,rem 是余数。
指令格式都差不多,基本就是靠 func 码确定变体。
因为两个32位数乘积是64位数,一条指令处理会比较复杂,因此分为两个指令计算低位高位。mulh得到高32位,mul得到低32位。
mul 结果为正,mulh应为全0. mul 结果为负,mulh应为全f。可以这样检测是否溢出。
h:两个数都是用符号。
hu:两个都无符号。
hsu:一个有符号一个无符号。
除法实现:比如如下/3实现,是乘以一个近似1/3数的解决方式。
比起 MIPS-32,用一个寄存器作为目标寄存器,其处理指令会更加复杂,以致架构性能较差,运行稍慢。
RV32F 和 RV32D
添加了新的浮点寄存器。
flw fld fsw fsd: 加载,写入(单精度,双精度)。
fxxx.s:运算指令,其中也包含平方根和大小值比较。
fmadd.s fmsub.d 这一类通常用于一些乘法后紧跟着加减的操作,比如矩阵运算。
单独加法指令比这种混合指令更准确因为乘法加法舍入两次,而加法只舍入一次。
混合指令需要4个寄存器,两个乘,一个加,一个dest嘛。格式如下:
上为F下为D。把func部分给换成rm了。
然后分支是通过赋值实现。
feq.s,feq.d,flt.s,flt.d,fle.s,fle.d ,为 true 赋值为1。
flt x5,f1,f2 # 如果 f1 < f2,则 x5 = 1;否则 x5 = 0
bne x5,x0,Exit # 如果 x5!= 0,则跳转到 Exit
浮点扩展也支持一些类型转换,比如 fcvt .w .d 是 from double to signed integer.
w:signed integer
wu:unsigned integer
s:float point
d:double point
fmv 是数据移入寄存器或者从寄存器中取出。
符号注入:把第一个源操作数除了符号位复制到dest。
fsgnj:结果符号位和第二个源操作数符号位一样。
fsgnjn:第二个源操作数符号位取反。
fsgnjx:两个源操作数符号位异或。
所以实际上:
fmv.s rd, rs
fsgnj.s rd, rs, rs # 以上两个一样
fmv.d rd, rs
dsgnj.s rd, rs, rs # 以上两个一样
fneg.s rd, rs
fsgnjn.s rd, rs, rs # 以上两个一样
fabs.s rd,rs
fsgnjx.s rd, rs, rs # 以上两个一样,因为00 11异或都是0
fclass 是分类指令,读取判断 rs 属于以下的哪一种,并且把对应值写入 rd 低10位上(把其中一位设为1,其他位全部为0)。分类对数学库运算很有帮助。