仔细观察

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

电路里经常用补码来表示有符号整数,求一个负数的补码表示最直接的方法是将对应的正数取反再加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的电路优化确实可以,不是一般代码可以比得上的。我猜测虽然用了减法器,但是减数是常数,所以实际使用的资源可能会低一些。

posted on 2024-04-28 14:28  注意看  阅读(5)  评论(0编辑  收藏  举报