电路里经常用补码来表示有符号整数,求一个负数的补码表示最直接的方法是将对应的正数取反再加1。如果要写一个参数化的求补码的模块,则代码如下:
module cal_complement#(
parameter WIDTH = 8
)(
input [WIDTH-1:0] din,
output [WIDTH-1:0] dout);
assign dout = ~(din - 1);
endmodule
此模块需要用到一个加法器,如果位宽较大可能时序上有些差并且所需资源较多。在阅读CSAPP的时候,了解到一种新的求补码的方式:从LSB到MSB寻找第一个为1的位置,然后从该位置的下一个位置开始直到MSB全都取反,就可以得到该数的补码非。我忽然联想到不用加法器也可以实现求负数的补码。
首先需要构建一个mask,该mask生成的规则是,从LSB到MSB的第一个为1的位置的下一个位置开始直到MSB都置1,其他位置置0。例如对于二进制数4'b0110,对应的mask为4'b1100。然后将该mask与原数做按位异或运算即可得到补码。负数做此运算会得到对应的正数的补码。
基于上述思路,模块的代码如下:
module cal_complement#(
parameter WIDTH = 8
)(
input [WIDTH-1:0] din,
output [WIDTH-1:0] dout
);
wire [WIDTH-1:0] inv_mask_w;
assign inv_mask_w = {din[WIDTH-2:0]|inv_mask_w[WIDTH-2:0],1'b0};
assign dout = din^inv_mask_w;
endmodule
代码中inv_mask[0]
直接置0即可,因为不管din
的LSB是0还是1,inv[0]
都应该置0。
接下来我设置位宽为32位然后综合了一下,很不幸,结果显示采用第二种写法确实会降低面积,但是降低的程度很有限,但是时序上第一种反而要比第二种要好一些,不得不说DesignWare的电路优化确实可以,不是一般代码可以比得上的。我猜测虽然用了减法器,但是减数是常数,所以实际使用的资源可能会低一些。
标签:din,dout,补码,inv,mask,开销,WIDTH,电路 From: https://www.cnblogs.com/lzhj/p/18163680