
利用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) begin
if(reset) begin
wr_flag <= 0;
addra <= 0;
end else begin
wr_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) begin
if(reset) begin
buffer0_status <= 0;
buffer1_status <= 0;
end else begin
buffer0_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) begin
if(reset) begin
addrb <= 0;
rd_flag <= 0;
end else begin
addrb <= 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) begin
if(reset) begin
rd_en_d <= 0;
rd_flag_d <= 0;
end else begin
rd_en_d <= rd_en;
rd_flag_d <= rd_flag;
end
end
//输出
always@(posedge clk or posedge reset) begin
if(reset) begin
valid_o <= 0;
data_o <= 0;
end else begin
valid_o <= rd_en_d;
data_o <= rd_flag_d ? buffer1_dout : buffer0_dout;
end
end
endmodule
