在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