FPGA位宽调整模块

在fpga程序中,寄存器变量向不同模块的输入会涉及位宽进行扩展或截取,于是为了方便使用,设计了一个位宽调整模块

该模块主要由位宽截断模块bit_truncation和位宽扩展模块bit_extension组成

复制代码
//`define	param_constrain
module bit_truncation#(
	parameter	BW_IN		= 'd18	,
	parameter	BW_OUT		= 'd4	,
	parameter	SIGNED		= 'b1	,
	parameter	ROUND		= 'b1	,
	parameter	DIRECTION	= 'b1
)(
	input		[BW_IN - 1:0]	i_data	,
	output		[BW_OUT - 1:0]	o_data
    );
	
	`ifdef param_constrain
	generate
        if(ROUND > 1) begin
			$error("bit_truncation parameter ROUND only supports [0,1]");
			$fatal(1,"bit_truncation parameter ROUND only supports [0,1]");
		end
		if(DIRECTION > 1) begin
			$error("bit_truncation parameter DIRECTION only supports [0,1]");
			$fatal(1,"bit_truncation parameter DIRECTION only supports [0,1]");
		end
		if(SIGNED > 1) begin
			$error("bit_truncation parameter SIGNED supports [0,1]");
			$fatal(1,"bit_truncation parameter SIGNED supports [0,1]");
		end
    endgenerate	
	`endif
	
	generate
		localparam	TRUNC_BITS = BW_IN - BW_OUT;
			
		wire	w_carrybit;
		
		if(BW_IN == BW_OUT)	
			assign o_data = i_data;
		else 
			case(DIRECTION)
				0:begin
					assign  w_carrybit = (SIGNED & i_data[BW_IN - 1]) ? (i_data[TRUNC_BITS - 1] & (| i_data[TRUNC_BITS - 2:0])) : i_data[TRUNC_BITS - 1]; 
					assign	o_data = ROUND ? i_data[BW_IN - 1:TRUNC_BITS] + w_carrybit : i_data[BW_IN - 1:TRUNC_BITS]; 
				end
				1:begin
					assign	o_data = SIGNED ? {i_data[BW_IN - 1], i_data[BW_OUT - 2:0]} : i_data[BW_OUT - 1:0];
				end
			endcase
    endgenerate
	
	
endmodule

//`define	param_constrain

module bit_extension# (
	parameter	BW_IN		= 'd16 	,
	parameter	BW_OUT		= 'd19	,
	parameter	SIGNED		= 'b1	
)(
	input	[BW_IN - 1:0]	i_data	,
	output	[BW_OUT - 1:0]	o_data
    );
	
	`ifdef param_constrain
	generate
		if(SIGNED > 1) begin
			$error("bit_extension parameter SIGNED only supports [0,1]");			
			$fatal(1,"bit_extension parameter SIGNED only supports [0,1]");
        end
		if(BW_IN > BW_OUT) begin
			$error("bit_extension parameter BW_IN exceeds BW_OUT");
			$fatal(1,"bit_extension parameter BW_IN exceeds BW_OUT");
		end
	endgenerate	
	`endif
	
	generate
		if(BW_IN == BW_OUT)
			assign 	o_data = i_data;
		else 
			assign	o_data = SIGNED ? {{(BW_OUT - BW_IN){i_data[BW_IN - 1]}}, i_data} : {{(BW_OUT - BW_IN){1'b0}}, i_data};
	endgenerate
	
endmodule

bit_extension模块比较好办,其对外有3个传递参数分别代表输入位宽(bit width)BW_IN,输出位宽BW_OUT和符号位选择SIGNED,当SIGNED为1时就意味着进行位宽扩展的数据是有符号数,反之按照无符号规则进行扩展。

bit_truncation模块对外的参数多了一个ROUND代表截断后是否进行四舍五入,DIRECTION代表截断的方向是从左到右还是从右到左,当其为1代表从右到左截断,比如将1011截断为011。

整合到一个模块如下:

参数START_BIT 代表从右向左数第几位作为基准(相当于从该位进行截断),并以此来输出BW_OUT位的输出,如果START_BIT + BW_OUT > BW_IN则自动进行扩展,如果小于则自动进行从右到左的截断

复制代码
module bit_slicer#(
	parameter	START_BIT	= 0	,
	parameter	BW_IN		= 10,
	parameter	BW_OUT		= 5	,
	parameter	SIGNED		= 1	,
	parameter	ROUND		= 1
)(
	input	[BW_IN - 1:0]	i_data	,
	output	[BW_OUT - 1:0]	o_data
    );
	
	generate
		if(START_BIT == 0) begin
			if(BW_IN == BW_OUT)
				assign o_data = i_data;
			else if(BW_IN > BW_OUT) 
				bit_truncation#(
					.BW_IN		(BW_IN		),
					.BW_OUT		(BW_OUT		),
					.SIGNED		(SIGNED		),
					.ROUND		(ROUND		),
					.DIRECTION	(1			))
				inst_u(
					.i_data	(i_data)	,
					.o_data	(o_data)
				);
			else 
				bit_extension# (
					.BW_IN	(BW_IN	),
					.BW_OUT	(BW_OUT	),
					.SIGNED	(SIGNED	))
				inst_u(
					.i_data	(i_data	)	,
					.o_data	(o_data	)
				);
		end
		else begin
			if(BW_IN - START_BIT == BW_OUT)
				assign o_data = i_data[BW_IN - 1:START_BIT];
			else if(BW_IN - START_BIT < BW_OUT) begin
				
				localparam	BW_TMP = BW_IN - START_BIT;
			
				wire	[BW_TMP - 1:0]	w_tmp;
				
				bit_truncation#(
					.BW_IN		(BW_IN	),
					.BW_OUT		(BW_TMP	),
					.SIGNED		(SIGNED	),
					.ROUND		(ROUND	),
					.DIRECTION	(0		))
				inst_u0(
					.i_data	(i_data	)	,
					.o_data	(w_tmp	)
				);
				
				bit_extension# (
					.BW_IN	(BW_TMP	),
					.BW_OUT	(BW_OUT	),
					.SIGNED	(SIGNED	))
				inst_u1(
					.i_data	(w_tmp	)	,
					.o_data	(o_data	)
				);				
			end
			else begin
				
				localparam	BW_TMP = BW_OUT + START_BIT;
				
				wire	[BW_TMP - 1:0]	w_tmp;
			
				bit_truncation#(
					.BW_IN		(BW_IN	),
					.BW_OUT		(BW_TMP	),
					.SIGNED		(SIGNED	),
					.ROUND		(ROUND	),
					.DIRECTION	(1		))
				inst_u0(
					.i_data	(i_data	)	,
					.o_data	(w_tmp	)
				);		
	
				bit_truncation#(
					.BW_IN		(BW_TMP	),
					.BW_OUT		(BW_OUT	),
					.SIGNED		(SIGNED	),
					.ROUND		(ROUND	),
					.DIRECTION	(0		))
				inst_u1(
					.i_data	(w_tmp	)	,
					.o_data	(o_data	)
				);	
			end
		end
	endgenerate
	
endmodule

tb文件

复制代码
module trunc_tb();

	parameter	BW_IN		= 'd12	;
	parameter	BW_OUT		= 'd8	;
	parameter	SIGNED		= 'b1	;
	parameter	ROUND		= 'b1	;
	parameter	DIRECTION	= 'b1   ;
	wire		[BW_IN - 1:0]	i_data	= 12'habc;
	wire		[BW_OUT - 1:0]	o_data	;
bit_truncation#(
	.BW_IN		(BW_IN		),
	.BW_OUT		(BW_OUT		),
	.SIGNED		(SIGNED		),
	.ROUND		(ROUND		),
	.DIRECTION	(DIRECTION	))
bit_truncation_U (
	i_data	,
	o_data
);
endmodule

module tb();


	parameter	START_BIT	= 4		;
	parameter	BW_IN		= 16	;
	parameter	BW_OUT		= 6		;
	parameter	SIGNED		= 1		;
	parameter	ROUND		= 0 	;

	wire	[BW_IN - 1:0]	i_data = 16'h5bcd;
	wire	[BW_OUT - 1:0]	o_data;


bit_slicer#(
	.START_BIT	(START_BIT	),
	.BW_IN		(BW_IN		),
	.BW_OUT		(BW_OUT		),
	.SIGNED		(SIGNED		),
	.ROUND		(ROUND		))
u(
	i_data	,
	o_data
);

endmodule