您的位置:首页 > Web前端

视频处理vout_frame_buffer_ctrl模块的理解

2016-10-01 12:34 183 查看
/*

vout_frame_buffer_ctrl这个模块主要实现:场输出信号&FIFO&ddr之间的协议关系
给出场时序,也就是帧输出信号,计算出具体的读写长度和读写地址,读请求信号给DDR。
在VGA时钟,帧时序的控制下,有规律地从DDR读出的数据是存在FIFO中,然后从FIFO输出
数据到VGA端口引脚。 DDR中的数据是存放一帧数据,BURST模块是不停地读数据到FIFO中,
DDR的读时钟是非常快的,VGA的是74.25MHZ,二者之间,只有帧同步的,

*/
module vout_frame_buffer_ctrl#(
parameter MEM_DATA_BITS = 64
)(
input rst_n, ///*复位*/
input vout_clk, ///*视频时钟*/
input vout_vs, ///*视频输出场同步*/
input vout_rd_req, ///*视频输出数据读取请求*/
output[23:0] vout_data, ///*视频输出读取的数据*/
input[11:0] vout_width, ///*视频输出的宽度,指的是存在存储器内的视频宽度*/
input[11:0] vout_height, ///*视频输出的高度*/

input mem_clk, ///*存储器接口时钟*/
output reg rd_burst_req, ///*存储器接口读取请求*/
output reg[9:0] rd_burst_len, ///*存储器接口读取长度*/
output reg[23:0] rd_burst_addr, ///*存储器接口读取首地址*/
input rd_burst_data_valid, ///*存储器接口返回读取数据有效*/
input[MEM_DATA_BITS - 1:0] rd_burst_data, ///*存储器接口返回的读取数据*/
input burst_finish ///*本次读取完成*/
);
localparam BURST_LEN = 10'd128; ///*定义突发读取的长度,如果数据达不到这个长度则按数据实际长度读取 */
localparam BURST_IDLE = 3'd0; ///*读取控制状态机:空闲状态*/
localparam BURST_ONE_LINE_START = 3'd1; ///*读取控制状态机:开始读取一行视频 */
localparam BURSTING = 3'd2; ///*读取控制状态机:正在完成一次突发读取 */
localparam BURST_END = 3'd3; ///*读取控制状态机:一次突发读取操作完成 */
localparam BURST_ONE_LINE_END = 3'd4; ///*读取控制状态机:一行视频数据读取完成*/
reg[2:0] burst_state = 3'd0; ///*读取控制状态机:当前状态 */
reg[2:0] burst_state_next = 3'd0; ///*读取控制状态机:下一个状态 */
reg[11:0] burst_line = 12'd0; ///*本轮(每场一轮)已经读取的总行数 */
reg frame_flag;
reg vout_vs_mem_clk_d0;
reg vout_vs_mem_clk_d1;
reg[10:0] remain_len;
wire[11:0] wrusedw;

/*在这里搞了一个4096的缓冲区,DDR的数据读到线性FIFO中*/
/*FIFO的写时钟为DDR的内存时钟,读时钟为VGA的像素时钟, 为一行数据的FIFO*/
fifo_4096_24 fifo_4096_24_m0(
.aclr(frame_flag),
.data(rd_burst_data[23:0]), // FIFO的先进数据,即写入的数据
.rdclk(vout_clk), // VGA输出时钟,即为读时钟
.rdreq(vout_rd_req), // VGA的DE位,数据有效标志
.wrclk(mem_clk), // DDR的时钟,即为写时钟
.wrreq(rd_burst_data_valid), // DDR返回来的数据读有效标志,作为请示写FIFO标志
.q(vout_data), // FIFO的先出的数据,即为读出的数据,这个数据会送到VGA端口引脚上去
.rdempty(),
.rdusedw(),
.wrfull(),
.wrusedw(wrusedw));

/*ddr2读取首地址计算,需要注意的是视频并不是连续读取的,而是按照“行”为单元存取*/
/*
rd_burst_addr <= {3'd0,burst_line[9:0],11'd0};//24bit ddr addr
24位地址, 11'd0为列地址,也就是2048个单元格(64位位宽,合8个字节,每一个字节为8位数据)
burst_line[9:0] 为行地址,视频的宽度为720P,这个的数据为1024个行数。
数据的存储格式为:一个像素为3个字节,存在一个单元格中(64位,浪费了40位),这样就形了一帧
数据的存储。
rd_burst_addr <= rd_burst_addr + {15'd0,BURST_LEN[8:0]};
每一次的突发读取是128个长度,所以加上128
*/
always@(posedge mem_clk or negedge rst_n)
begin
if(!rst_n)
rd_burst_addr <= 24'd0;
else if(burst_state_next == BURST_ONE_LINE_START)
rd_burst_addr <= {3'd0,burst_line[9:0],11'd0};//24bit ddr addr
else if(burst_state_next == BURST_END && burst_state != BURST_END)
rd_burst_addr <= rd_burst_addr + {15'd0,BURST_LEN[8:0]};
else
rd_burst_addr <= rd_burst_addr;
end

/////////////////////////////////////////////////////

always@(posedge mem_clk)
begin
vout_vs_mem_clk_d0 <= vout_vs;
vout_vs_mem_clk_d1 <= vout_vs_mem_clk_d0;
frame_flag <= vout_vs_mem_clk_d0 && ~vout_vs_mem_clk_d1; // 产生帧标志
end

/*产生burst_state状态标志*/
always@(posedge mem_clk or negedge rst_n)
begin
if(!rst_n)
burst_state <= BURST_IDLE;
else if(frame_flag)
burst_state <= BURST_IDLE;
else
burst_state <= burst_state_next;
end

/*读写burst_state状态机*/
/*这部分是关键内容,根据敏感时序置状态机。主要完成DDR读数据到FIFO中,读取时
是一次性读128个字节,一个像素行数据分多次读取
这个模块是在各种条件下(FRAME_FLAG, VGA_OUT),不停地读DDR数据到FIFO中,

*/
always@(*)
begin
case(burst_state)
BURST_IDLE: ///*如果fifo空间够写入一次突然地数据,就完成一行数据的第一次突发*/
if(wrusedw < (4095 - BURST_LEN))/*判断fifo空间*/
burst_state_next <= BURST_ONE_LINE_START;
else
burst_state_next <= BURST_IDLE;
BURST_ONE_LINE_START:
burst_state_next <= BURSTING;
BURSTING: ///*完成一次突发读操作*/
if(burst_finish)
burst_state_next <= BURST_END;
else
burst_state_next <= BURSTING;
BURST_END:
if(remain_len == 11'd0)/*判断一行数据是否读完,没有读完则等待fifo以完成下次读*/
burst_state_next <= BURST_ONE_LINE_END;
else if(wrusedw < (4095 - BURST_LEN))/*判断fifo空间*/
burst_state_next <= BURSTING;
else
burst_state_next <= BURST_END;
BURST_ONE_LINE_END:/*完成一行数据的读取*/
burst_state_next <= BURST_IDLE;
default:
burst_state_next <= BURST_IDLE;
endcase
end

/*burst_line的总行数计数器赋值*/
always@(posedge mem_clk or negedge rst_n)
begin
if(!rst_n)
burst_line <= 12'd0;
else if(frame_flag)
burst_line <= 12'd0;
else if(burst_state_next == BURST_ONE_LINE_END && burst_state == BURST_END)
burst_line <= burst_line + 12'd1;/*每次完成一行数据的读取burst_line加1*/
else
burst_line <= burst_line;
end

/*计算每行剩余数据*/
always@(posedge mem_clk or negedge rst_n)
begin
if(!rst_n)
remain_len <= 11'd0;
else if(burst_state_next == BURST_ONE_LINE_START)
remain_len <= vout_width[10:0]; // 一行开始,置为像素的个数,如1280
else if(burst_state_next == BURST_END && burst_state != BURST_END)
if(remain_len < BURST_LEN)
remain_len <= 11'd0; // ???, 直接给0, 当不是128的倍数时,为1366,则是不是有错
else
remain_len <= remain_len - BURST_LEN; // 大于128,减掉一次性128个突发读取
else
remain_len <= remain_len;
end

/*计算突发读取的长度*/
always@(posedge mem_clk or negedge rst_n)
begin
if(!rst_n)
rd_burst_len <= 10'd0;
else if(burst_state_next == BURSTING && burst_state != BURSTING)
if(remain_len > BURST_LEN)
rd_burst_len <= BURST_LEN;
else
rd_burst_len <= remain_len; // 这是直接给出来remain_len,只有0,128二种值
else
rd_burst_len <= rd_burst_len;
end

/*读请求信号的发出与撤销*/
/*这里产生读DDR的请求信号,根据burst_state状态*/
always@(posedge mem_clk or negedge rst_n)
begin
if(!rst_n)
rd_burst_req <= 1'd0;
else if(burst_state_next == BURSTING && burst_state != BURSTING)
rd_burst_req <= 1'b1; // 读开始
else if(burst_finish || burst_state == BURST_IDLE || rd_burst_data_valid)
rd_burst_req <= 1'b0; // 读结束
else
rd_burst_req <= rd_burst_req;
end

endmodule
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐