利用bram形成双缓冲,如下图配置所示:
wr_flag 表明 buffer0写 还是 buffer1写 rd_flag 表明 buffer0读 还是 buffer1读
通过写入逻辑控制(结合wr_finish) 写哪个buffer ;写地址 进而控制ip的写使能
通过状态缓存来跳转buffer的写和读
通过读取逻辑(结合rd_finish) 读哪个buffer ;读地址
最后通过时序控制,调整输出数据及数据有效对齐
`timescale 1ns / 1ps
//
// Description: 水平镜像
//
module image_horizion_flip(input wire clk,input wire reset,input wire [10:0] img_width,input wire valid_i,input wire [23:0] data_i,output reg valid_o,output reg [23:0] data_o
);///有关写逻辑部分的变量申明
reg wr_flag ;
reg [10:0] addra ;
//一行像素写入buffer结束标志
wire wr_finish;
assign wr_finish = (valid_i && (addra == img_width - 1))? 1'b1 : 1'b0;
//buffer0/1的写使能
wire buffer0_wr, buffer1_wr;
assign buffer0_wr = valid_i&(~wr_flag);
assign buffer1_wr = valid_i&wr_flag;///有关读逻辑部分的变量申明
reg buffer0_status, buffer1_status;
//读数据使能 读取数据 缓存完一行,启动读数据。
wire rd_en;
assign rd_en = buffer0_status|buffer1_status;reg rd_flag;
reg [10:0] addrb;
//一行像素读出buffer结束标志
wire rd_finish;
assign rd_finish = rd_en&&(addrb == img_width - 1) ? 1'b1 : 1'b0;wire [23:0] buffer0_dout, buffer1_dout;
reg rd_en_d;
reg rd_flag_d;
///写入逻辑//
//写入地址,wr_flag等于0时,写入buffer0,等于1时,写入buffer1
always@(posedge clk or posedge reset) beginif(reset) beginwr_flag <= 0;addra <= 0;end else beginwr_flag <= wr_finish ? ~wr_flag : wr_flag;addra <= wr_finish ? 0 : (valid_i ? (addra + 1'b1) : addra);end
end/缓存状态保存///
//先判断buffer是否写满,写满开始读;继而判断是否读空,读空则开始写
always@(posedge clk or posedge reset) beginif(reset) beginbuffer0_status <= 0;buffer1_status <= 0;end else beginbuffer0_status <= ((~wr_flag) && wr_finish) ? 1'b1 :(((~rd_flag) && rd_finish) ? 1'b0 : buffer0_status);buffer1_status <= (wr_flag && wr_finish) ? 1'b1:((rd_flag && rd_finish) ? 1'b0 : buffer1_status);end
end /读取逻辑///
//读地址一般逻辑
always@(posedge clk or posedge reset) beginif(reset) beginaddrb <= 0;rd_flag <= 0;end else beginaddrb <= rd_en ? ((addrb == img_width - 1) ? 'b0 : addrb + 1'b1) : addrb;rd_flag <= rd_finish ? ~rd_flag : rd_flag;end
end
//镜像读数据地址 水平镜像,从右往左
wire [10:0] addrb_flip;
assign addrb_flip = img_width - 1 - addrb;bram_line_buffer u0 (.clka (clk ), // input wire clka.wea (buffer0_wr ), // input wire [0 : 0] wea.addra(addra ), // input wire [10 : 0] addra.dina (data_i ), // input wire [23 : 0] dina.clkb (clk ), // input wire clkb.addrb(addrb_flip ), // input wire [10 : 0] addrb.doutb(buffer0_dout) // output wire [23 : 0] doutb
);bram_line_buffer u1 (.clka (clk ), // input wire clka.wea (buffer1_wr ), // input wire [0 : 0] wea.addra(addra ), // input wire [10 : 0] addra.dina (data_i ), // input wire [23 : 0] dina.clkb (clk ), // input wire clkb.addrb(addrb_flip ), // input wire [10 : 0] addrb.doutb(buffer1_dout) // output wire [23 : 0] doutb
);//输出数据打一拍延时
always@(posedge clk or posedge reset) beginif(reset) beginrd_en_d <= 0;rd_flag_d <= 0;end else beginrd_en_d <= rd_en;rd_flag_d <= rd_flag;endend
//输出
always@(posedge clk or posedge reset) beginif(reset) beginvalid_o <= 0;data_o <= 0;end else beginvalid_o <= rd_en_d;data_o <= rd_flag_d ? buffer1_dout : buffer0_dout;end
end endmodule