除数为常数的除法实现
除数为常数的除法实现,当然除数为变量的方式是兼容常数的运算,只是针对常数运算,通常也有几种方法,供大家参考。
方法一: 把除数转化为小数,采用乘法运算,比如:
a[15:0] / 8'd24;
十进制小数转换成二进制小数采用"乘2取整,顺序排列"法。具体做法是:用2乘十进制小数,可以得到积,将积的整数部分取出,再用2乘余下的小数部分,又 得到一个积,再将积的整数部分取出,如此进行,直到积中的整数部分为零,或者整数部分为1,此时0或1为二进制的最后一位。或者达到所要求的精度为止。
然后把取出的整数部分按顺序排列起来,先取的整数作为二进制小数的高位有效位,后取的整数作为低位有效位。
例如:0.7=(0.1 0110 0110...)B
0.7*2=1.4========取出整数部分1
0.4*2=0.8========取出整数部分0
0.8*2=1.6========取出整数部分1
0.6*2=1.2========取出整数部分1
0.2*2=0.4========取出整数部分0
0.4*2=0.8========取出整数部分0
0.8*2=1.6========取出整数部分1
0.6*2=1.2========取出整数部分1
0.2*2=0.4========取出整数部分0
1/24 = 0.04167 = 00001010
0.04167*2 = 0.08334 ========取出整数部分0
0.08334*2 = 0.16698 ========取出整数部分0
0.16698*2 = 0.33336 ========取出整数部分0
0.33336*2 = 0.66672 ========取出整数部分0
0.66672*2 = 1.33344 ========取出整数部分1
0.33344*2 = 0.66688 ========取出整数部分0
0.66688*2 = 1.33376 ========取出整数部分1
0.33376*2 = 0.66752 ========取出整数部分0
a/8'd24 = (a * (00001010)) >> 8
方法二: 现在DC综合工具对于/ 在常数运算时,是可以识别,并且优化效果与方法一相当,所以可以采用
quotient = a/B的方式进行常数除法运算。
方法三: 对于被除数除数范围比较小的情况,可以采用查找表的方式,比如被除数为a[2:0] 除数为3,则通过查找表方式完成,Verilog示例如下:
always @(*) begin
case(a)
3'h0 : quotient = 3'h0;
3'h1 : quotient = 3'h0;
3'h2 : quotient = 3'h0;
3'h3 : quotient = 3'h1;
3'h4 : quotient = 3'h1;
3'h5 : quotient = 3'h1;
3'h6 : quotient = 3'h1;
3'h7 : quotient = 3'h1;
default : quotient = 3'h0;
endcase
end
上述二进制移位除法,最大的问题就是运算的Cycle会随被除数位宽增加而增加,因此在除法运算延时要求较高场景,可以使用DW的除法器,DW的除法器包括支持流水插拍的版本,可以帮助提升工作时钟频率。
几种除法器在统一工艺,按照500MHz目标综合,52bits/25bits,数据对比:
除法器 面积(um2) 最大Slack 工作时钟周期
二级制移位除法 1000 -0.4 53
DW_div 43692 -15.42 2
DW_div_pipe 50008 -4.386 4
DW_div_seq 11980 -1.0348 10
综上,大家根据自己实际需求进行除法器实现策略。