视频处理模块vin_frame_buffer_ctrl的解读

`timescale 1ps/1ps
/*
模块完成16bit的YC数据的64bit的数据对齐,然后写入FIFO,
有帧写入状态机完成64bit数据写入ddr2
*/
module vin_frame_buffer_ctrl
 #(
	parameter MEM_DATA_BITS = 64
) 
(
	input rst_n,                                    /*复位 */
	input vin_clk,                                  /*视频输入时钟 */
	input vin_vs,                                   /*视频输入场同步 */
	input vin_de,                                   /*视频输入数据有效 */
	input[23:0] vin_data,                           /*视频输入数据YC */
	input[11:0] vin_width,                          /*视频输入宽度*/
	input[11:0] vin_height,                         /*视频输入高度*/
	
	input mem_clk,                                  /*存储器接口:时钟*/
	output reg wr_burst_req,                        /*存储器接口:写请求*/
	output reg[9:0] wr_burst_len,                   /*存储器接口:写长度*/
	output reg[23:0] wr_burst_addr,                 /*存储器接口:写首地址 */
	input wr_burst_data_req,                        /*存储器接口:写数据数据读指示 */
	output[MEM_DATA_BITS - 1:0] wr_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;                   /*状态机状态:正在处理一次ddr2写操作 */
localparam BURST_END = 3'd3;                  /*状态机状态:一次ddr2写操作完成*/
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;					/*已经写入ddr2的行计数*/
reg[11:0] remain_len = 12'd0;					/*当前视频一行数据的剩余数据个数*/
reg vin_vs_mem_clk_d0 = 1'b0;
reg vin_vs_mem_clk_d1 = 1'b0;
reg frame_flag = 1'b0;
wire[11:0] rdusedw;
fifo_4096_24 fifo_4096_24_m0(
	.aclr(frame_flag),						//  FRAME清除标志
	.data(vin_data),						// 写入数据
	.rdclk(mem_clk),						// DDR内存读时钟
	.rdreq(wr_burst_data_req),				// DDR需要的读请求信号	
	.wrclk(vin_clk),						// 外部写入时钟
	.wrreq(vin_de),							// 外部写入请求
	.q(wr_burst_data[23:0]),				// DDR读出的数据
	.rdempty(),
	.rdusedw(rdusedw),						// DDR读出的长度
	.wrfull(),
	.wrusedw()
);


/*突发写首地址的产生*/
always@(posedge mem_clk or negedge rst_n)
begin
	if(!rst_n)
		wr_burst_addr <= 24'd0;
	else if(burst_state_next == BURST_ONE_LINE_START)
		wr_burst_addr <= {3'd0,burst_line[9:0],11'd0};//24bit ddr addr
	else if(burst_state_next == BURST_END  && burst_state != BURST_END)   // 当前不是BURST_END,下一个才是BURST_END
		wr_burst_addr <= wr_burst_addr + BURST_LEN[7:0]; // 指针指向下一闪的突发写地址
	else
		wr_burst_addr <= wr_burst_addr;  // 保持
end


/*产生帧标志*/
/*产生帧开始标志,只是一个mem_clk周期才为高,其余时间为低*/
always@(posedge mem_clk)
begin
	vin_vs_mem_clk_d0 <= vin_vs;
	vin_vs_mem_clk_d1 <= vin_vs_mem_clk_d0;
	frame_flag <= vin_vs_mem_clk_d0 && ~vin_vs_mem_clk_d1;
end


/*每一帧都将状态机强行进入BURST_IDLE状态*/

/*frame_flag在为1时,第一次为IDLE,然后为0时,是置为burst_state_next,
注意这里:在为0时,mem_clk为敏感信号,burst_state和burst_state_next是连接的二个状态
*/
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

/*下面的操作都应是在frame_flag为0时, 二个状态字,
burst_state_next是在burst_state的下一状态,根据当前的burst_state来指定
burst_state_next的值,由于mem_clk都为二者的敏感信号,用非阻塞赋值,相当于
以下的结构,

always@(posedge mem_clk or negedge rst_n)
begin
		
		...
			burst_state_next <= BURST_END;
			burst_state <= burst_state_next;
		...
end

	这样的话,burst_state_next是burst_state的下一状态

*/
always@(*)
begin
	case(burst_state)
		BURST_IDLE:/*如果FIFO有足够的数据则完成一行第一次写操作*/
			if(rdusedw > BURST_LEN[7:0])
				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:/*写操作完成时判断一行数据是否已经完全写入ddr2,如果完成则进入空闲状态,等待第二行数据*/
			if(remain_len == 12'd0)
				burst_state_next <= BURST_ONE_LINE_END;
			else if(rdusedw >= BURST_LEN[7:0])// || (remain_len <= BURST_LEN && rdusedw == remain_len - 10'd1))//һ��ͻ������,��һ������һ��ͻ��
				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 == BURST_ONE_LINE_END)//每次一行写完burst_line加1
		burst_line <= burst_line + 12'd1;
	else
		burst_line <= burst_line;
end

/*remain_len产生,每一行写开始时等于byte_per_line,如果一行数据小于一次写的最大长度,
一次写完,则remain_len = 0,否则减去最大写长度*/
always@(posedge mem_clk or negedge rst_n)
begin
	if(!rst_n)
		remain_len <= 12'd0;
	else if(burst_state_next == BURST_ONE_LINE_START)
		remain_len <= vin_width;
	else if(burst_state_next == BURST_END && burst_state != BURST_END)
		if(remain_len < BURST_LEN)
			remain_len <= 12'd0;
		else
			remain_len <= remain_len - BURST_LEN;	
	else
		remain_len <= remain_len;
end


/*突发长度产生,如果一行的剩余数据大于最大写长度,则突发长度是BURST_LEN,否则就等于剩余数据长度*/
always@(posedge mem_clk or negedge rst_n)
begin
	if(!rst_n)
		wr_burst_len <= 10'd0;
	else if(burst_state_next == BURSTING && burst_state != BURSTING)
		if(remain_len > BURST_LEN)
			wr_burst_len <= BURST_LEN;
		else
			wr_burst_len <= remain_len;
	else
		wr_burst_len <=  wr_burst_len;
end


/*ddr2写请求信号的产生于撤销*/
always@(posedge mem_clk or negedge rst_n)
begin
	if(!rst_n)
		wr_burst_req <= 1'd0;
	else if(burst_state_next == BURSTING && burst_state != BURSTING)
		wr_burst_req <= 1'b1;
	else if(burst_finish  || wr_burst_data_req || burst_state == BURST_IDLE)
		wr_burst_req <= 1'b0;
	else
		wr_burst_req <= wr_burst_req;
end

endmodule 


其中关于remain_len 长度的问题,有以下分析:

/*remain_len产生,每一行写开始时等于byte_per_line,如果一行数据小于一次写的最大长度,
一次写完,则remain_len = 0,否则减去最大写长度*/
always@(posedge mem_clk or negedge rst_n)
begin
if(!rst_n)
remain_len <= 12'd0;
else if(burst_state_next == BURST_ONE_LINE_START)
remain_len <= vin_width;
else if(burst_state_next == BURST_END && burst_state != BURST_END)  // 正在BURSTING中
if(remain_len < BURST_LEN)
remain_len <= 12'd0; // 如果小于128的话,则表示下一次没有余留数据,直接为0
else
remain_len <= remain_len - BURST_LEN; // 大于BURST_LEN 128长度的话,减去128
else
remain_len <= remain_len;
end
/*突发长度产生,如果一行的剩余数据大于最大写长度,则突发长度是BURST_LEN,否则就等于剩余数据长度*/
always@(posedge mem_clk or negedge rst_n)
begin
if(!rst_n)
wr_burst_len <= 10'd0;
else if(burst_state_next == BURSTING && burst_state != BURSTING)
if(remain_len > BURST_LEN)
wr_burst_len <= BURST_LEN;
else
wr_burst_len <= remain_len;  // 突发写的长度不足够128
else
wr_burst_len <=  wr_burst_len;
end


remain_len <= 12'd0; 为0时,是在最后的不足128个字节时为0,注意状态机表示当前在BURSTING的状态。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值