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_constraingenerateif(ROUND > 1) begin$error("bit_truncation parameter ROUND only supports [0,1]");$fatal(1,"bit_truncation parameter ROUND only supports [0,1]");endif(DIRECTION > 1) begin$error("bit_truncation parameter DIRECTION only supports [0,1]");$fatal(1,"bit_truncation parameter DIRECTION only supports [0,1]");endif(SIGNED > 1) begin$error("bit_truncation parameter SIGNED supports [0,1]");$fatal(1,"bit_truncation parameter SIGNED supports [0,1]");endendgenerate `endifgeneratelocalparam TRUNC_BITS = BW_IN - BW_OUT;wire w_carrybit;if(BW_IN == BW_OUT) assign o_data = i_data;else case(DIRECTION)0:beginassign 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]; end1:beginassign o_data = SIGNED ? {i_data[BW_IN - 1], i_data[BW_OUT - 2:0]} : i_data[BW_OUT - 1:0];endendcaseendgenerateendmodule
//`define param_constrainmodule 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_constraingenerateif(SIGNED > 1) begin$error("bit_extension parameter SIGNED only supports [0,1]"); $fatal(1,"bit_extension parameter SIGNED only supports [0,1]");endif(BW_IN > BW_OUT) begin$error("bit_extension parameter BW_IN exceeds BW_OUT");$fatal(1,"bit_extension parameter BW_IN exceeds BW_OUT");endendgenerate `endifgenerateif(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};endgenerateendmodule
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);generateif(START_BIT == 0) beginif(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 ));endelse beginif(BW_IN - START_BIT == BW_OUT)assign o_data = i_data[BW_IN - 1:START_BIT];else if(BW_IN - START_BIT < BW_OUT) beginlocalparam 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 )); endelse beginlocalparam 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 )); endendendgenerateendmodule
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