module AXI_FULL_M #
	(
        parameter integer VIDEO_LENGTH      = 1920                            ,
        parameter integer VIDEO_HIGTH       = 1080                            ,
        parameter integer PIXEL_WIDTH       = 32                              ,
		parameter integer CTRL_ADDR_WIDTH	= 28                              ,
		parameter integer DQ_WIDTH	        = 32                              ,
        parameter integer M_AXI_BRUST_LEN   = 8                               ,
        parameter integer VIDEO_BASE_ADDR   = 2'd0                            
	)
	(

		input wire                                    DDR_INIT_DONE           ,
		input wire                                    M_AXI_ACLK              ,
		input wire                                    M_AXI_ARESETN           ,
		//Ð´µØÖ·Í¨µÀ¡ý                                                              
		output wire [CTRL_ADDR_WIDTH-1 : 0]           M_AXI_AWADDR            ,
		output wire                                   M_AXI_AWVALID           ,
		input wire                                    M_AXI_AWREADY           ,
		//Ð´Êý¾ÝÍ¨µÀ¡ý                                                              
		input wire                                    M_AXI_WLAST             ,
		input wire                                    M_AXI_WREADY            ,
		//Ð´ÏìÓ¦Í¨µÀ¡ý                                                              
		//¶ÁµØÖ·Í¨µÀ¡ý                                                              
		output wire [CTRL_ADDR_WIDTH-1 : 0]           M_AXI_ARADDR            ,
		output wire                                   M_AXI_ARVALID           ,
		input wire                                    M_AXI_ARREADY           ,
		//¶ÁÊý¾ÝÍ¨µÀ¡ý                                                              
		input wire                                    M_AXI_RLAST             ,
		input wire                                    M_AXI_RVALID            ,
        //video
        input wire                                    vs_in                   ,
        input wire                                    vs_out                  ,
        //fifoÐÅºÅ
        input wire  [8 : 0]                           wfifo_rd_water_level    ,
        output                                        wfifo_rd_req            /* synthesis PAP_MARK_DEBUG="1" */,
        output                                        wfifo_pre_rd_req        /* synthesis PAP_MARK_DEBUG="1" */,
        input wire  [8 : 0]                           rfifo_wr_water_level    ,
        output                                        rfifo_wr_req            ,
        output reg                                    r_fram_done             ,
        //ÆäËû
        input       [19 : 0]                          wr_addr_min             ,//Ð´Êý¾Ýddr×îÐ¡µØÖ·0µØÖ·¿ªÊ¼Ëã£¬1920*1080*16 = 33177600 bits
        input       [19 : 0]                          wr_addr_max             ,//Ð´Êý¾Ýddr×î´óµØÖ·£¬Ò»¸öµØÖ·´æ32Î» 33177600/32 = 1036800 = 20'b1111_1101_0010_0000_0000
        output reg                                    r_wr_rst                ,
        output reg                                    r_rd_rst                ,
        output reg [1 : 0]                            w_fifo_state/* synthesis PAP_MARK_DEBUG="1" */,
        output reg [1 : 0]                            r_fifo_state/* synthesis PAP_MARK_DEBUG="1" */,
        output wire [19 : 0]                          wr_addr_cnt/* synthesis PAP_MARK_DEBUG="1" */
	);
/************************************************************************/

/*******************************²ÎÊý***************************************/
parameter    IDLE          =   'd0,
             WRITE_START   =   'd1,
             WRITE_ADDR    =   'd2,
             WRITE_DATA    =   'd3,
             READ_START    =   'd1,
             READ_ADDR    =    'd2,
             READ_DATA     =   'd3;




/*******************************¼Ä´æÆ÷***************************************/


reg [CTRL_ADDR_WIDTH - 1 : 0]    r_m_axi_awaddr;//µØÖ·¼Ä´æÆ÷
reg                              r_m_axi_awvalid;
reg                              r_m_axi_wlast;
reg                              r_m_axi_wvalid;
reg [CTRL_ADDR_WIDTH*8 - 1 : 0]  r_m_axi_araddr;
reg                              r_m_axi_arvalid/* synthesis PAP_MARK_DEBUG="1" */;
reg [7 : 0]                      r_wburst_cnt;
reg [7 : 0]                      r_rburst_cnt;
reg [DQ_WIDTH*8 - 1 : 0]         r_m_axi_rdata;

reg [19 : 0]                     r_wr_addr_cnt/* synthesis PAP_MARK_DEBUG="1" */;
reg [19 : 0]                     r_rd_addr_cnt/* synthesis PAP_MARK_DEBUG="1" */;
reg [1 : 0]                      r_wr_addr_page/* synthesis PAP_MARK_DEBUG="1" */;
reg [1 : 0]                      r_rd_addr_page/* synthesis PAP_MARK_DEBUG="1" */;
reg [1 : 0]                      r_wr_last_page/* synthesis PAP_MARK_DEBUG="1" */;
reg [1 : 0]                      r_rd_last_page/* synthesis PAP_MARK_DEBUG="1" */;

reg                              r_wr_done;//Ò»Ö¡Í¼Ïñ´«ÊäÍê³ÉÐÅºÅ
reg                              r_rd_done;
reg                              r_wfifo_rd_req;
reg                              r_wfifo_pre_rd_req;
reg                              r_wfifo_pre_rd_flag;
reg                              r_rfifo_wr_req;
//¸´Î»ÐÅºÅ
reg                              r_vs_in_d0;
reg                              r_vs_in_d1; 
reg                              r_vs_out_d0;                            
reg                              r_vs_out_d1;     
//reg                              r_wr_rst/* synthesis PAP_MARK_DEBUG="1" */;
//reg                              r_rd_rst/* synthesis PAP_MARK_DEBUG="1" */;                       
/*******************************Íø±íÐÍ***************************************/

/*******************************×éºÏÂß¼­***************************************/
//Ò»Ð©³£ÓÃ½Ó¿ÚÊÇ³£Á¿£¬¸ù¾Ý¶¥²ãÄ£¿éÖ±½Ó¸³Öµ¾ÍºÃ
//Ð´µØÖ·
assign M_AXI_AWADDR     =   {4'b0 , VIDEO_BASE_ADDR , r_wr_addr_page , r_wr_addr_cnt};//27-22¸ßÎ»0£¬21-20 Ö¡»º´æÒ³Êý£¬ 19-0 Ð´µØÖ·¼ÆÊý
assign M_AXI_AWVALID    =   r_m_axi_awvalid;
//Ð´Êý¾Ý
assign wfifo_rd_req     =   M_AXI_WLAST ? 1'b0 : M_AXI_WREADY;//r_wfifo_rd_req;
assign wfifo_pre_rd_req =   r_wfifo_pre_rd_req;//µ±µØÖ·ÓÐÐ§ºó½øÐÐÔ¤¶Á³öÒ»´ÎÊý¾Ý
//¶ÁµØÖ·
assign M_AXI_ARADDR     =   {4'b0 , VIDEO_BASE_ADDR , r_rd_addr_page , r_rd_addr_cnt};//27-22¸ßÎ»0£¬21-20 Ö¡»º´æÒ³Êý£¬ 19-0 ¶ÁµØÖ·¼ÆÊý
assign M_AXI_ARVALID    =   r_m_axi_arvalid;
assign rfifo_wr_req     =   M_AXI_RLAST ? 1'b0 : M_AXI_RVALID;//r_rfifo_wr_req;

assign wr_addr_cnt = r_wr_addr_cnt;
//¶ÁÊý¾Ý
//ÄÚ´æÇÐ»»
/*******************************½ø³Ì***************************************/
//×¥È¡Ö¡Í¬²½ÉÏÉýÑØ£¬·½±ãºóÐø¸´Î»²Ù×÷
always @(posedge M_AXI_ACLK ) begin
    if(!M_AXI_ARESETN ) begin
        r_vs_in_d0 <= 'd0;
        r_vs_in_d1 <= 'd0;
        r_vs_out_d0 <= 'd0;
        r_vs_out_d1 <= 'd0;
    end
    else begin
        r_vs_in_d0 <= vs_in;
        r_vs_in_d1 <= r_vs_in_d0;
        r_vs_out_d0 <= vs_out;
        r_vs_out_d1 <= r_vs_out_d0;
    end
end
//Âö³å¸´Î»
always @(posedge M_AXI_ACLK ) begin
    if(!M_AXI_ARESETN ) begin
        r_wr_rst <= 'd0; 
    end
    else if(r_vs_in_d0 && (!r_vs_in_d1)) begin//×¥È¡ÉÏÉýÑØ£¬d0Îª¸ß£¬d1Îª1Ê±À­¸ß¸´Î»
        r_wr_rst <= 'd1;
    end
    else if(r_wr_addr_cnt == wr_addr_min) begin //µ±µØÖ·Î»¹éÁãÊ±½áÊø¸´Î»
        r_wr_rst <= 'd0;
    end
    else begin
        r_wr_rst <= r_wr_rst;
    end
end

always @(posedge M_AXI_ACLK ) begin
    if(!M_AXI_ARESETN ) begin
        r_rd_rst <= 'd0; 
    end
    else if(r_vs_out_d0 && (!r_vs_out_d1)) begin//×¥È¡ÉÏÉýÑØ£¬d0Îª¸ß£¬d1Îª1Ê±À­¸ß¸´Î»
        r_rd_rst <= 'd1;
    end
    else if(r_rd_addr_cnt == wr_addr_min) begin //µ±µØÖ·Î»¹éÁãÊ±½áÊø¸´Î»
        r_rd_rst <= 'd0;
    end
    else begin
        r_rd_rst <= r_rd_rst;
    end
end
//µØÖ·Ò³¸Ä±ä
always @(posedge M_AXI_ACLK ) begin
    if(!M_AXI_ARESETN ) begin//¸´Î»ºóÎª0Ê±
        r_wr_addr_page <= 2'b0;
        r_wr_last_page <= 2'b0;
    end 
    else if(r_wr_done) begin
        r_wr_last_page <= r_wr_addr_page ;
        r_wr_addr_page <= r_wr_addr_page + 1;                                 //×îºóÒ»´ÎÍ»·¢´«ÊäÍê³É£¬Ò»Ö¡Í¼Ïñ´«ÊäÍê³É
        if(r_wr_addr_page == r_rd_addr_page) begin
            r_wr_addr_page <= r_wr_addr_page + 1;
        end
    end
end
always @(posedge M_AXI_ACLK ) begin
    if(!M_AXI_ARESETN ) begin//¸´Î»ºóÎª0Ê±
        r_rd_addr_page <= 2'b0;
        r_rd_last_page <= 2'b0;
    end 
    else if(r_rd_done) begin//Ö¡»º´æ¶ÁÍêºó£¬¶ÔµØÖ·Ò³½øÐÐÇÐ»»£¬¶ÔÉÏÒ»´ÎÐ´µÄÖ¡»º´æ½øÐÐ¶Á£¬Èç¹ûµ±Ç°Ð´ÈëµÄÖ¡»º´æºÍÉÏÒ»´ÎµÄÖ¡»º´æÎ´±ä£¨Ö¡»º´æÃ»ÓÐÐ´Íê£©£¬ÔòÖØ¸´¶ÁÉÏÒ»´ÎµÄ¶ÁÖ¡»º´æ
        r_rd_last_page <= r_rd_addr_page;
        r_rd_addr_page <= r_wr_last_page;
        if(r_rd_addr_page == r_wr_addr_page) begin
            r_rd_addr_page <= r_rd_last_page ;
        end
    end
end
//Ò»¸öalways¿é×îºÃ¿ØÖÆÒ»¸öreg
//Ð´µØÖ·Í¨µÀ
always @(posedge M_AXI_ACLK ) begin
   if(!M_AXI_ARESETN ) begin//ÓÐÐ§ÐÅºÅºÍ×¼±¸ÐÅºÅ¶¼Îª1Ê±£¬ÓÐÐ§ÐÅºÅ¹é0
        r_m_axi_awvalid <= 1'b0;
        r_wr_addr_cnt <= 20'b0;
        r_wr_done <= 1'b0;
        r_fram_done <= 1'b0;
    end 
    else if (r_wr_rst) begin
        r_wr_addr_cnt <= wr_addr_min;
        r_m_axi_awvalid <= 1'b0;
    end
    else if (DDR_INIT_DONE) begin
        if(r_wr_addr_cnt < wr_addr_max - M_AXI_BRUST_LEN * 8 ) begin //Ð´ÈëµÄµØÖ·Ð¡ÓÚ×î´óµØÖ·¼õÈ¥Ò»´ÎÍ»·¢´«ÊäµÄ×ÜÁ¿£¨len*axi_data_width(256)/32£©
            r_wr_done<= 1'b0; 
            if(M_AXI_AWVALID && M_AXI_AWREADY) begin         
                r_m_axi_awvalid <= 1'b0;
                r_wr_addr_cnt <= r_wr_addr_cnt + M_AXI_BRUST_LEN * 8;
            end
            else if(w_fifo_state == WRITE_ADDR) begin
                r_m_axi_awvalid <= 1'b1;
            end
        end
        else if(r_wr_addr_cnt >= wr_addr_max - M_AXI_BRUST_LEN * 8 ) begin//×îºóÒ»´ÎÍ»·¢´«ÊäÊ±£¬µØÖ·¼ÆÊý¹éÁã            
            if(M_AXI_AWVALID && M_AXI_AWREADY) begin         
                r_m_axi_awvalid <= 1'b0;
                r_wr_addr_cnt <= wr_addr_min;
                r_wr_done<= 1'b1;  
                r_fram_done <= 1'b1;     
            end
            else if(w_fifo_state == WRITE_ADDR) begin
                r_m_axi_awvalid <= 1'b1;
            end
        end  
    end
    else begin
        r_m_axi_awvalid <= r_m_axi_awvalid;//ÆäËû×´Ì¬±£³Ö²»¶¯
        r_wr_done <= r_wr_done;
        r_wr_addr_cnt <= 20'b0;
    end
end

//Ð´Êý¾ÝÍ¨µÀ
always @(posedge M_AXI_ACLK )begin//Ð´Í»·¢¼ÆÊý
    if(!M_AXI_ARESETN || M_AXI_WLAST)begin
        r_wburst_cnt <= 'd0;
        r_wfifo_rd_req <= 1'b0;
    end
    else if (M_AXI_WREADY) begin
        r_wburst_cnt <= r_wburst_cnt + 1 ;
        r_wfifo_rd_req <= 1'b1;
        if (r_wburst_cnt == M_AXI_BRUST_LEN - 1'b1) begin//µ±¼ÆÊýµ½7Ê±£¬²»ÔÙÊ¹ÄÜ¶Á³öwfifo
            r_wfifo_rd_req <= 1'b0;
        end
    end
    else begin
        r_wburst_cnt <= r_wburst_cnt;
        r_wfifo_rd_req <= 'd0;
    end
end
//Ô¤¶ÁWFIFO£¬Çå³ýfifoÊä³ö½Ó¿ÚÉÏÒ»´ÎÊý¾Ý
always @(posedge M_AXI_ACLK )begin//Ð´Í»·¢¼ÆÊý
    if(!M_AXI_ARESETN ||(!(r_vs_in_d0) && r_vs_in_d1))begin//Ã¿´ÎVSÏÂ½µÑØ¶ÔÆä¸´Î»
        r_wfifo_pre_rd_req <= 'd0;
        r_wfifo_pre_rd_flag <= 'd0;
    end
    else if(M_AXI_AWVALID && M_AXI_AWREADY && (r_wfifo_pre_rd_flag == 'd0)) begin
        r_wfifo_pre_rd_req <= 'd1;
        r_wfifo_pre_rd_flag <= 'd1;
    end
    else begin
        r_wfifo_pre_rd_req <= 'd0;
    end
end
//¶ÁµØÖ·
always @(posedge M_AXI_ACLK ) begin//¶ÁµØÖ·ÓÐÐ§
    if(!M_AXI_ARESETN)begin
        r_m_axi_arvalid <= 'd0;//¸´Î»¡¢À­¸ßºó¹éÁã
        r_rd_addr_cnt <= 20'b0;
        r_rd_done <= 'd0;
    end
    else if(r_rd_rst)begin
        r_rd_addr_cnt <= wr_addr_min;
        r_m_axi_arvalid <= 'd0;
    end
    else if (DDR_INIT_DONE) begin//DDR³õÊ¼»¯½áÊøÇÒÓÐÒ»Ö¡Í¼ÏñÒÑ¾­´æ´¢ºÃºó,
        if(r_rd_addr_cnt < wr_addr_max - M_AXI_BRUST_LEN * 8) begin
            r_rd_done <= 'd0;
            if(M_AXI_ARVALID && M_AXI_ARREADY) begin//´Ó»úÏàÓ¦ºóÀ­µÍ£¬Ð´µØÖ·ÓÐÐ§À­µÍ£¬Í¬Ê±µØÖ·×ÔÔö            
                r_m_axi_arvalid <= 1'b0;
                r_rd_addr_cnt <= r_rd_addr_cnt + M_AXI_BRUST_LEN * 8;
            end
            else if(r_fifo_state == READ_ADDR) begin
                r_m_axi_arvalid <= 1'b1;
            end
        end
        else if(r_rd_addr_cnt == wr_addr_max - M_AXI_BRUST_LEN * 8) begin
            if(M_AXI_ARVALID && M_AXI_ARREADY) begin//×îºó´«ÊäÍê³Éºó¹éÁã            
                r_m_axi_arvalid <= 1'b0;
                r_rd_addr_cnt <= wr_addr_min;
                r_rd_done <= 'd1;
            end
            else if(r_fifo_state == READ_ADDR) begin
                r_m_axi_arvalid <= 1'b1;
            end            
        end

    end
    else begin
        r_m_axi_arvalid <= r_m_axi_arvalid;
        r_rd_addr_cnt <= r_rd_addr_cnt;
    end
end
//¶ÁÊý¾Ý
always @(posedge M_AXI_ACLK )begin//ÊÕµ½validºóÊ¹ÄÜfifo´«ÊäÊý¾Ý
    if(!M_AXI_ARESETN || M_AXI_RLAST)begin
        r_rfifo_wr_req <= 'd0;
        r_rburst_cnt <= 'd0;
    end
    else if (M_AXI_RVALID) begin
        r_rfifo_wr_req <= 1'b1;
        r_rburst_cnt <= r_rburst_cnt + 1'b1;
        if (r_rburst_cnt == M_AXI_BRUST_LEN - 1'b1) begin//µ±¼ÆÊýµ½7Ê±£¬²»ÔÙÊ¹ÄÜ¶Á³öwfifo
            r_rfifo_wr_req <= 1'b0;
        end
    end
    else begin
        r_rfifo_wr_req <= 'd0;
        r_rburst_cnt <= r_rburst_cnt;
    end
end

/*******************************×´Ì¬»ú***************************************/
//ÎªÁËÊµÏÖË«ÏòÍ¬Ê±´«Êä»¥²»Ó°Ïì£¬ËùÒÔ¶ÁÐ´×´Ì¬µ¥¶À×ö×´Ì¬»úÊ¹ÓÃ
//DDR3Ð´×´Ì¬»ú
always @(posedge M_AXI_ACLK ) begin
    if(~M_AXI_ARESETN || r_wr_rst)
        w_fifo_state    <= IDLE;
    else begin
        case(w_fifo_state)
            IDLE: 
            begin
                if(DDR_INIT_DONE)
                    w_fifo_state <= WRITE_START ;
                else
                    w_fifo_state <= IDLE;
            end
            WRITE_START:
            begin
//                if (r_wr_rst) begin
//                    w_fifo_state <= WRITE_START;
//                end
                if(wfifo_rd_water_level > M_AXI_BRUST_LEN) begin//µ±wfifoÖÐ¶ÁË®Î»¸ßÓÚÍ»·¢³¤¶È£¨4£©ÊÇ£¬¿ªÊ¼Í»·¢´«Êä
                    w_fifo_state <= WRITE_ADDR;   //Ìøµ½Ð´²Ù×÷
                end
                else if((r_wr_addr_cnt >= wr_addr_max - M_AXI_BRUST_LEN * 8) && (wfifo_rd_water_level >= M_AXI_BRUST_LEN - 1'b1)) begin//ÓÉÓÚÖ®Ç°Ô¤¶ÁÁËÒ»´Î£¬ËùÒÔÕâÀïÐèÒª-1
                    w_fifo_state <= WRITE_ADDR;
                end                
                else begin
                    w_fifo_state <= w_fifo_state;
                end            
            end
            WRITE_ADDR:
            begin
                if(M_AXI_AWVALID && M_AXI_AWREADY)
                    w_fifo_state <= WRITE_DATA;  //Ìøµ½Ð´Êý¾Ý²Ù×÷
                else
                    w_fifo_state <= w_fifo_state;   //Ìõ¼þ²»Âú×ã£¬±£³Öµ±Ç°Öµ
            end
            WRITE_DATA: 
            begin
                //Ð´µ½Éè¶¨µÄ³¤¶ÈÌøµ½µÈ´ý×´Ì¬
                if(M_AXI_WLAST)//M_AXI_WREADY && (r_wburst_cnt == M_AXI_BRUST_LEN - 1)
                    w_fifo_state <= WRITE_START;  //Ð´µ½Éè¶¨µÄ³¤¶ÈÌøµ½µÈ´ý×´Ì¬
                else
                    w_fifo_state <= w_fifo_state;  //Ð´Ìõ¼þ²»Âú×ã£¬±£³Öµ±Ç°Öµ
            end
            default:
            begin
                w_fifo_state     <= IDLE;
            end
        endcase
    end
end
//DDR¶Á×´Ì¬»ú
always @(posedge M_AXI_ACLK ) begin
    if(~M_AXI_ARESETN || r_rd_rst)
        r_fifo_state    <= IDLE;
    else begin
        case(r_fifo_state)
            IDLE: 
            begin
                if(DDR_INIT_DONE && r_fram_done) begin
                    r_fifo_state <= READ_START ;
                end
                else begin
                    r_fifo_state <= IDLE;
                end
            end
            READ_START:
            begin
//                if(r_rd_rst) begin
//                    r_fifo_state <= READ_START;       
//                end
                if(rfifo_wr_water_level < VIDEO_LENGTH*PIXEL_WIDTH/128)//µ±wfifoÖÐ¶ÁË®Î»Ð¡ÓÚ240£¬¿ªÊ¼Í»·¢´«Êä£¬1920*32*2/256 = 240£¨120¸öÍ»·¢´«ÊäÊý¾Ý£©240/8 = 30´ÎÍ»·¢´«Êä
                    r_fifo_state <= READ_ADDR;   //Ìøµ½Ð´²Ù×÷
                else
                    r_fifo_state <= r_fifo_state;
            end
            READ_ADDR:
            begin
                if(M_AXI_ARVALID && M_AXI_ARREADY)
                    r_fifo_state <= READ_DATA;  //Ìøµ½Ð´Êý¾Ý²Ù×÷
                else
                    r_fifo_state <= r_fifo_state;   //Ìõ¼þ²»Âú×ã£¬±£³Öµ±Ç°Öµ
            end
            READ_DATA: 
            begin
                //Ð´µ½Éè¶¨µÄ³¤¶ÈÌøµ½µÈ´ý×´Ì¬
                if(M_AXI_RLAST ) //&& (r_rburst_cnt == M_AXI_BRUST_LEN - 1)
                    r_fifo_state <= READ_START;  //Ð´µ½Éè¶¨µÄ³¤¶ÈÌøµ½µÈ´ý×´Ì¬
                else
                    r_fifo_state <= r_fifo_state;  //Ð´Ìõ¼þ²»Âú×ã£¬±£³Öµ±Ç°Öµ
            end
            default:
            begin
                r_fifo_state     <= IDLE;
            end
        endcase
    end
end

endmodule