2.二维求和模块设计(Sum_2D) 二维求和模块需例化一个一维的求和Sum_1D模块,同时生成行列 同步电路。将数据流接入Sum_1D模块进行行方向的求和,同时将行方 向的求和结果依次打入行缓存,对齐后输出进行列方向上的求和工 作。 需要设计的参数不仅包括数据位宽和处理窗口的宽度,二维方向 上的操作还包括图像的宽度和高度参数。 模块定义如下:
module sum_2d(
rst_n, //异步复位信号
clk, //同步时钟din_valid, //输入数据有效
din, //输入数据流
dout, //输出数据流
vsync, //输入场同步信号
vsync_out, //输出场同步信号
is_boarder, //输出边界信息
dout_valid //输出数据有效
);
//参数定义
parameter DW = 14; //数据位宽参数
parameter KSZ = 3; //求和窗口参数
parameter IH = 512; //图像高度
parameter IW = 640; //图像宽度
//首先例化一个行方向上的求和模块
wire [2*DW-1:0] sum_row; //行求和信号
sum_1d #(DW,KSZ)
row_sum(
.clk(clk),
.din(din),
.din_valid(valid),
.dout(sum_row), //输出行求和结果
.dout_valid(row_valid) //行求和结果有效
);
//例化(KSZ-1)个行缓存
generate
begin : line_buffer_inst
genvar i;for (i = 0; i <= KSZ - 2; i = i + 1)
begin : line_buf
if (i == 0)
begin : row_1st //第一个行缓存,输入数据为行求和结
果
always @(*) line_dinl[i]<= sum_row[DW -
1:0];
always @(*) line_dinh[i]<= sum_row[2 * DW -
1:DW];
assign line_wrenl[i]= row_valid;
assign line_wrenh[i]= row_valid;
end
if ((~(i == 0))) //其余行缓存,输入数据为上一行的
输出
begin : row_others
always @(*) line_dinl[i]<= line_doutl[i -
1];
always @(*) line_dinh[i]<= line_douth[i -
1];
assign line_wrenh[i]= line_rdenh[i - 1];
assign line_wrenl[i]= line_rdenl[i - 1];
end
assign line_rdenl[i]= buf_pop_en[i]& row_valid;
assign line_rdenh[i]= buf_pop_en[i]& row_valid;
//行缓存装满一行后打出
always @(posedge clk)
beginif (rst_all == 1'b1)
buf_pop_en[i]<= #1 1'b0;
else if (line_countl[i]== IW)
buf_pop_en[i]<= #1 1'b1;
end
//输入数据缓存
always @(*) data_temp_l [i]<= line_dinl[i];
//行缓存低半部分
line_buffer #(DW,IW)
line_buf_l(
.rst(rst_all),
.clk(clk),
.din(data_temp_l[i]),
.dout(line_doutl[i]),
.wr_en(line_wrenl[i]),
.rd_en(line_rdenl[i]),
.empty(line_emptyl[i]),
.full(line_fulll[i]),
.count(line_countl[i])
);
always @(*) data_temp_h[i]<= line_dinh[i];
//行缓存高半部分
line_buffer #(DW,IW)
line_buf_h(
.rst(rst_all),
.clk(clk),
.din(data_temp_h[i]),.dout(line_douth[i]),
.wr_en(line_wrenh[i]),
.rd_en(line_rdenh[i]),
.empty(line_emptyh[i]),
.full(line_fullh[i]),
.count(line_counth[i])
);
end
end
endgenerate
//列方向求和 窗口尺寸为5*5
generate
if (KSZ == 5)begin : sum_ksz_5
//首先得到之前已经缓冲的4行的求和结果
assign sum_row1 = ({line_douth[0][DW -
1:0],line_doutl[0][DW
- 1:0]});
assign sum_row2 = ({line_douth[1][DW -
1:0],line_doutl[1][DW
- 1:0]});
assign sum_row3 = (((buf_pop_en[2]) == 1'b1)) ?
({line_douth[2]
[DW - 1:0],line_doutl[2][DW - 1:0]}) :
{2*DW-1+1{1'b0}};
assign sum_row4 = (((buf_pop_en[3]) == 1'b1)) ?
({line_douth[3]
[DW - 1:0],line_doutl[3][DW - 1:0]}) :2*DW-1+1{1'b0}};
assign dout_valid_temp = line_valid_r[2 + 2];
//运算延时为4个时钟
assign dout_valid_temp = line_valid_r[2 + 2];
always @(posedge clk)
begin
line_valid_r[4:0]<=
({line_valid_r[3:0],line_rdenl[1]});
//缓存5拍行读取信号
if ((line_rdenl[1]) == 1'b1)
sum_row_r <= #1 sum_row; //缓存当前行
if ((line_rdenl[1]) == 1'b1)
begin
sum_1_2 <= #1 sum_row1 + sum_row2; //1,2
行相加
sum_3_4 <= #1 sum_row3 + sum_row4; //3,4
相加
end
if ((line_valid_r[0]) == 1'b1)
begin
sum_0_1_2 <= #1 sum_col_r+sum_1_2;
//当前行与1,2行求和后相加
sum_3_4_r <= #1 sum_3_4; //3,4行求和结
果缓存
end
if ((line_valid_r[1]) == 1'b1)
sum_all <= #1 sum_0_1_2 + sum_3_4_r;//得到5行的求和结果
end
end
endgenerate
wire[DW*2-1:0] dout_reg;
//边界置零处理
assign dout_reg = ((is_boarder_tmp == 1'b1)) ?
{DW+1{1'b0}} :
dout_temp;
assign dout = dout_temp_r;
assign dout_valid = dout_valid_temp_r;
assign is_boarder = is_boarder_r;
//求和结果打一拍后输出
always @(posedge clk)
begin
if (rst_all == 1'b1)
begin
dout_temp_r <= #1 {2*DW-1+1{1'b0}};
dout_valid_temp_r <= #1 1'b0;
valid_r <= #1 1'b0;
is_boarder_r <= 1'b0;
end
else
begin
if (dout_valid_temp == 1'b1)
dout_temp_r <= #1 dout_reg;
elsedout_temp_r <= {2*DW-1+1{1'b0}};
dout_valid_temp_r <= #1 dout_valid_temp;
valid_r <= #1 valid;
is_boarder_r <= is_boarder_tmp;
end
end
/*输入行计数*/
always @(posedge clk)
begin
if (rst_all == 1'b1)
in_line_cnt <= #1 {11{1'b0}};
else if ((( ~ (valid))) == 1'b1 & valid_r ==
1'b1)
in_line_cnt <= #1 in_line_cnt +
11'b00000000001;
end
/*溢出行行列计数*/
always @(posedge clk)
begin
if (rst_all == 1'b1)
begin
flush_line <= #1 1'b0;
flush_cnt <= #1 {16{1'b0}};
end
else
begin
if (flush_cnt >= ((IW - 1)))flush_cnt <= #1 {16{1'b0}};
else
if (flush_line == 1'b1)
flush_cnt <= #1 flush_cnt +
16'b0000000000000001;
if (flush_cnt >= ((IW - 1)))
flush_line <= #1 1'b0;
else
if (in_line_cnt >= IH & out_line_cnt <
((IH - 1)))
flush_line <= #1 1'b1;
end
end
/*输出行行列计数*/
always @(posedge clk)
begin
if (rst_all == 1'b1)
begin
out_pixel_cnt <= #1 {16{1'b0}};
out_line_cnt <= #1 {11{1'b0}};
end
else
begin
if (dout_valid_temp_r == 1'b1 & (( ~
(dout_valid_temp))) ==
1'b1)out_line_cnt <= #1 out_line_cnt +
11'b00000000001;
else
out_line_cnt <= #1 out_line_cnt;
if(dout_valid_temp_r==1'b1&(( ~
(dout_valid_temp)))==1'b1)
out_pixel_cnt <= #1 {16{1'b0}};
else
if (dout_valid_temp == 1'b1)
out_pixel_cnt<=#1
out_pixel_cnt+16'b0000000000000001;
end
end
//边界判决电路
assign is_boarder_tmp = ((dout_valid_temp == 1'b1 &
((out_pixel_cnt <=(((radius - 1)))) | (out_pixel_cnt >=
(((IW - radius)))) | (out_line_cnt <=(((radius - 1)))) |
(out_line_cnt >= (((IH - radius))))))) ? 1'b1 : 1'b0;
3.除法电路设计 除法电路将除法操作分为8个移位值的相加操作,总共需3个时钟 来完成8个数的相加。需要注意的是加法结果的位宽选择及移位溢出。
/*首先定义中间计算寄存器*/
reg [2*DW-1:0] Mean_temp;
reg [2*DW-1:0] Mean_temp1;
reg [2*DW:0] Mean_temp2;
reg [2*DW+5-1:0]Mean_temp3;
reg [2*DW+6-1:0]Mean_temp4;reg [2*DW+1-1:0]Mean_temp5;
reg [2*DW+6-1:0]Mean_temp6;
reg [2*DW+6-1:0]Mean_temp7;
wire [2*DW+6-1:0]Mean_temp8;
wire [DW-1:0] Mean_temp9;
wire [DW+3-1:0] Mean_temp10;
wire [2*DW+6-1:0]Mean_temp11;
wire [2*DW-1:0] Mean_out_temp;
generate
if (KSZ == 5)
begin : divide_25 /*除以25操作*/
always @(posedge clk or negedge rst_n)
if (((~(rst_n))) == 1'b1)/*复位清零*/
begin
Mean_temp <= {2*DW-1+1{1'b0}};
Mean_temp1 <= {2*DW-1+1{1'b0}};
Mean_temp2 <= {2*DW+1{1'b0}};
Mean_temp3 <= {2*DW+5-1+1{1'b0}};
Mean_temp4 <= {2*DW+6-1+1{1'b0}};
Mean_temp5 <= {2*DW+1-1+1{1'b0}};
Mean_temp6 <= {2*DW+6-1+1{1'b0}};
end
else
begin
//将二维求和结果缓存到Mean_temp
if ((sum_dout_valid_r[3]) == 1'b1)
Mean_temp <= #1 sum_dout_r[2];//下一拍开始计算
if ((sum_dout_valid_r[4]) == 1'b1)
begin
//计算Mean_temp (2-6 +2-7 )
Mean_temp1 <= #1 ({6'b000000,Mean_temp[2
* DW - 1:6]} +
({7'b0000000,Mean_temp[2*DW-1:7]}));
//计算Mean_temp (2-3 +2-4 )
Mean_temp2 <= #1 ({4'b0000,Mean_temp[2 *
DW - 1:3]}) +
({5'b00000,(Mean_temp[2*DW-1:4])});
//计算Mean_temp (2-1 +2-2 )
Mean_temp3 <=#1 ({6'b000000,Mean_temp[2
* DW - 1:1]}) +
({7'b0000000,(Mean_temp[2*DW-1:2])});
//计算Mean_temp (2-3 +2-5 )
Mean_temp4 <= #1 ({1'b0,Mean_temp[2 * DW
- 1:0],5'b00000})+
({3'b000,Mean_temp[2*DW-1:0],3'b000});
//下一拍开始计算上一拍的中间结果
if ((sum_dout_valid_r[5]) == 1'b1)
begin
Mean_temp5 <=#1(({1'b0,Mean_temp1}) +
Mean_temp2);
Mean_temp6 <=#1(({1'b0,Mean_temp3}) +
Mean_temp4);end
//下一拍开始计算上一拍的中间结果
if ((sum_dout_valid_r[6]) == 1'b1)
Mean_temp7 <= #1
({5'b00000,Mean_temp5}) + Mean_temp6;
end
end
end
endgenerate
//求和结果/1024得到除以25的结果
assign#1 Mean_temp8=((sum_is_boarder_r[6]==1'b0))?
((Mean_temp7>>10)) :
{2*DW+6-1+1{1'b0}};
//四舍五入操作
assign #1 Mean_temp9 = (((Mean_temp7[9]) == 1'b1)) ?
(Mean_temp8[DW -
1:0]+ 1'b1) : Mean_temp8[DW - 1:0];
//以下对输出结果保存三位小数
assign #1 Mean_temp11 = ((sum_is_boarder_r[6] == 1'b0)) ?
((Mean_temp7 >> 7)) : {2*DW+6-1+1{1'b0}};
assign #1 Mean_temp10 = (Mean_temp11[DW + 3 - 1:0]+
1'b1);
4.顶层设计 顶层设计非常简单,只选例化一个二维求和模块Sum_2D,并将其 输出做除法处理即可。代码如下:
//例化一个二维求和模块
Sum_2D #(DW,KSZ,IH,IW)window_sum(
.clk(clk),
.rst_n(rst_n),
.din_valid(din_valid),
.din(din),
.dout(sum_dout), //输出求和结果
.vsync(vsync),
.vsync_out(sum_vsync_out),
.is_boarder(sum_is_boarder), //输出边界信息
.dout_valid(sum_dout_valid)
);
/*缓存输出求和结果,求和边界信息和求和有效信息等*/
generate
begin : xhdl0
genvar i;
for (i = 0; i <= latency - 1; i = i + 1)
begin : buf_cmp_inst
if (i == 0)
begin : xhdl2
always @(posedge clk or negedge rst_n)
if (((~(rst_n))) == 1'b1)
begin
sum_dout_r[i]<= #1 {(latency - 1-2 *
DW -
1:0][0)+1{1'b0}};
sum_vsync_out_r[i]<= #1 1'b0;
sum_is_boarder_r[i]<= #1 1'b0;sum_dout_valid_r[i]<= #1 1'b0;
end
else
begin
sum_dout_r[i]<= #1 sum_dout;
sum_vsync_out_r[i]<= #1 sum_vsync_out;
sum_is_boarder_r[i]<= #1
sum_is_boarder;
sum_dout_valid_r[i]<= #1
sum_dout_valid;
end
end
if ((~(i == 0)))
begin : xhdl3
always @(posedge clk or negedge rst_n)
if (((~(rst_n))) == 1'b1)
begin
sum_dout_r[i]<= #1 {(latency - 1-2 *
DW -
1:0][0)+1{1'b0}};
sum_vsync_out_r[i]<= #1 1'b0;
sum_is_boarder_r[i]<= #1 1'b0;
sum_dout_valid_r[i]<= #1 1'b0;
end
else
begin
sum_dout_r[i]<= #1 sum_dout_r[i - 1];sum_vsync_out_r[i]<=#1
sum_vsync_out_r[i-1];
sum_is_boarder_r[i]<= #1
sum_is_boarder_
r[i - 1];
sum_dout_valid_r[i]<= #1 sum_dout_valid_
r[i - 1];
end
end
end
end
endgenerate
//输出相应信号
always @(posedge clk or negedge rst_n)
if (((~(rst_n))) == 1'b1)
begin
dout <= #1 {DW{1'b0}};
dout_valid <= #1 1'b0;
vsync_out <= #1 1'b0;
is_boarder <= #1 1'b0;
end
else
begin
dout <= #1 Mean_temp9;
dout_frac <= #1 Mean_temp10;
dout_valid <= #1 sum_dout_valid_r[6];
is_boarder <= #1 sum_is_boarder_r[6];vsync_out <= #1 sum_vsync_out_r[6];
end