本模块实现输入与输出位宽相同数据加法,并对结果进行四舍五入截位,对标matlab round函数。
`timescale 1ns/1ns
module data_in_width_out_width_add_round #
(
parameter DATA_WIDTH = 16
)
(
// 系统接口
input i_clk_sys ,
input i_rst ,
// 数据输入
input signed [DATA_WIDTH-1:0] i_din_a ,
input i_din_a_vld ,
input signed [DATA_WIDTH-1:0] i_din_b ,
input i_din_b_vld ,
// 数据输出
output signed [DATA_WIDTH-1:0] o_dout ,
output o_dout_vld
);
/****************************************************************************/
/* parameter
/****************************************************************************/
/****************************************************************************/
/* signal
/****************************************************************************/
logic signed [DATA_WIDTH-1+1:0] din_add_result ;
logic din_add_result_vld ;
logic signed [DATA_WIDTH-1+2:0] din_add_result_round ;
logic signed [DATA_WIDTH-1:0] din_add_result_truncate ;
logic din_add_result_vld_1dly ;
logic din_add_result_vld_2dly ;
/****************************************************************************/
/* process
/****************************************************************************/
always @(posedge i_clk_sys or posedge i_rst) // 数据加法
begin
if (i_rst)
begin
din_add_result <= {{DATA_WIDTH+1}{1'b0}};
end
else
begin
din_add_result <= i_din_a + i_din_b;
end
end
always @(posedge i_clk_sys)
begin
din_add_result_vld <= i_din_a_vld && i_din_b_vld;
end
always @(posedge i_clk_sys) // 数据四舍五入,根据要舍弃的位宽加不同的值
begin
if (din_add_result[DATA_WIDTH] == 1'b0) // 每次加法先扩充一个符号位,再对小数点位置进行 加减 0.5
begin
din_add_result_round <= {din_add_result[DATA_WIDTH],din_add_result + 1'b1};
end
else // 4'b1000}; +4bit 1是为了modelsim仿真,modelsim仿真规定小数至少3位
begin
din_add_result_round <= {din_add_result[DATA_WIDTH],din_add_result - 1'b1};
end
end
always @(posedge i_clk_sys or posedge i_rst) // 数据截位
begin
if (i_rst)
begin
din_add_result_truncate <= {DATA_WIDTH{1'b0}};
end
else if (din_add_result_round[DATA_WIDTH+1] == din_add_result_round[DATA_WIDTH])
begin // 如果数据没有溢出,舍弃最后一位,赋值; 先补充符号位,再取表示起始bit为1,包含bit1并往上升DATA_WIDTH-1位
din_add_result_truncate <= {din_add_result_round[DATA_WIDTH+1],din_add_result_round[1+ :(DATA_WIDTH-1)]};
end
else if (din_add_result_round[DATA_WIDTH+1] == 1'b0 && din_add_result_round[DATA_WIDTH] == 1'b1)
begin // 如果正数溢出了,就给一个设置的位宽bit正数最大值,'h7fff
din_add_result_truncate <= {1'b0,{(DATA_WIDTH-1){1'b1}}};
end
else if (din_add_result_round[DATA_WIDTH+1] == 1'b1 && din_add_result_round[DATA_WIDTH] == 1'b0)
begin // 如果负数溢出了,就给一个设置的位宽bit负数最大值,'h8000
din_add_result_truncate <= {1'b1,{(DATA_WIDTH-1){1'b0}}};
end
end
always @(posedge i_clk_sys) // 数据有效流水打拍
begin
din_add_result_vld_1dly <= din_add_result_vld;
din_add_result_vld_2dly <= din_add_result_vld_1dly;
o_dout <= din_add_result_truncate;
o_dout_vld <= din_add_result_vld_2dly;
end
endmodule
代码中如果直接截位,数据的输出将会产生直流,所以需要对数据的符号位进行判断,并进行处理。简单的思路如下:
1.数据先进行加法。
2.对加法后的结果,进行判断,正数+0.5,负数-0.5,此操作用于去除直流。
3.再对去除直流后的结果,进行需要的截位取值,例如16bit+16bit=17bit,而最终的输出结果,如果要16bit,那就去掉末位,也可以只要15bit,去掉末2bit,只要bit15-bit2。
上述代码是简单的例子处理,输入进来的两种数据同位宽,输出也用同位宽输出。后续可以改进。
审核编辑:刘清
全部0条评论
快来发表一下你的评论吧 !