视频处理vout_frame_buffer_ctrl模块的理解


/*
	
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 


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值