// ==============0ooo===================================================0ooo===========
// =  Copyright (C) 2014-2019 Gowin Semiconductor Technology Co.,Ltd.
// =                     All rights reserved.
// ====================================================================================
// 
//  __      __      __
//  \ \    /  \    / /   [File name   ] scaler_test_top.v
//   \ \  / /\ \  / /    [Description ] Scaler test module
//    \ \/ /  \ \/ /     [Timestamp   ] Friday Jul 17 14:00:30 2019
//     \  /    \  /      [version     ] 2.0
//      \/      \/
//
// ==============0ooo===================================================0ooo==========
// Code Revision History :
// ----------------------------------------------------------------------------------
// Ver:    |  Author    | Mod. Date    | Changes Made:
// ----------------------------------------------------------------------------------
// V1.0    | Caojie     | 07/17/19     | Initial version 
// ----------------------------------------------------------------------------------
// V1.1    | Caojie     | 10/12/19     | Scaler IP update 
// ----------------------------------------------------------------------------------
// V2.0    | Caojie     | 06/08/20     | Scaler IP update 
// ----------------------------------------------------------------------------------
// ==============0ooo===================================================0ooo==========

`include "vfb_defines.v"
`define	PARAM_DYNAMIC_CTRL //根据Scaler IP定义来确定是否 define

module scaler_test_top
(
	input            	I_clk 	      ,//50MHz
	input            	I_rst_n   	  ,
	output     [3:0] 	O_led     	  ,
	inout	            IO_adv7513_scl,
	inout	            IO_adv7513_sda,
	output              O_adv7513_clk ,
	output              O_adv7513_vs  ,
	output              O_adv7513_hs  ,
	output              O_adv7513_de  ,
	output      [23:0]  O_adv7513_data,
	output		[13:0] 	O_ddr_addr   ,
	output		[2:0]  	O_ddr_ba     ,
	output 				O_ddr_ras_n  ,
	output 				O_ddr_cas_n  ,
	output 				O_ddr_we_n   ,
	output 				O_ddr_clk    ,
	output 				O_ddr_clk_n  ,
	output 				O_ddr_cke    ,
	output 				O_ddr_odt    ,
	output 				O_ddr_reset_n,
	output 		[1:0] 	O_ddr_dqm    ,
	inout  		[15:0] 	IO_ddr_dq    ,
	inout  		[1:0] 	IO_ddr_dqs   ,
	inout  		[1:0] 	IO_ddr_dqs_n 
);

//=========================================================
//SRAM parameters
parameter IMAGE_SIZE          = 28'h080_0000;//--8MB,byte address  //frame base address
parameter BURST_WRITE_LENGTH  = 1024;  //bytes
parameter BURST_READ_LENGTH   = 1024;  //bytes
parameter ADDR_WIDTH          = 28;    //存储单元是byte，总容量=2^27*16bit = 2Gbit,增加1位rank地址，{rank[0],bank[2:0],row[13:0],cloumn[9:0]}
parameter DATA_WIDTH          = 128;   //与生成DDR3IP有关，此ddr3 2Gbit, x16， 时钟比例1:4 ，则固定128bit
parameter DQ_WIDTH            = 16;
parameter VIDEO_WIDTH	      = `DEF_VIDEO_WIDTH;  

//===========================================
wire        rst_n1;
wire        rst_n2;

//--------------------------
reg  [31:0] run_cnt;
wire        running;

//----------------------------------------
//ddr
wire        dma_clk  ;  

//-------------------------------------------------
//memory interface
wire                      cmd_ready          ;
wire[2:0]                 cmd                ;
wire                      cmd_en             ;
wire[5:0]                 app_burst_number   ;
wire[ADDR_WIDTH-1:0]      addr               ;
wire                      wr_data_rdy        ;
wire                      wr_data_en         ;//
wire                      wr_data_end        ;//
wire[DATA_WIDTH-1:0]      wr_data            ;   
wire[DATA_WIDTH/8-1:0]    wr_data_mask       ;   
wire                      rd_data_valid      ;  
wire                      rd_data_end        ;//unused 
wire[DATA_WIDTH-1:0]      rd_data            ;   
wire                      init_calib_complete; 

//===========================================
wire[11:0] vin_hres		;//输入水平分辨率
wire[11:0] vin_vres		;//输入垂直分辨率
wire[11:0] vout_hres	;//输出水平分辨率
wire[11:0] vout_vres	;//输出垂直分辨率
wire[23:0] hor_skfact	;//缩放因子，无符号定点数，8bit整数，16bit小数，vin_hor*(2^16)/vout_hor
wire[23:0] ver_skfact	;//缩放因子，无符号定点数，8bit整数，16bit小数，vin_ver*(2^16)/vout_ver

//-----------------------------------
wire        scaler_clk;
wire        clkout   ;
wire        clkoutd  ;
wire        pixel_clk/*synthesis syn_keep=1*/; //65MHz
wire        pll_locked;

wire        ch0_vs_in  ;
wire        ch0_hs_in  ;
wire        ch0_de_in  ;
wire [ 7:0] ch0_data_r ;
wire [ 7:0] ch0_data_g ;
wire [ 7:0] ch0_data_b ;

//-------------------------
//frame buffer in
wire                   ch0_vfb_clk_in ;
wire                   ch0_vfb_vs_in/*synthesis syn_keep=1*/  ;
wire                   ch0_vfb_de_in/*synthesis syn_keep=1*/  ;
wire [VIDEO_WIDTH-1:0] ch0_vfb_data_in/*synthesis syn_keep=1*/;

wire                   vout0fifo_empty;  

//-------------------
//syn_code
wire                   syn_off0_re;  // ofifo read enable signal
wire                   syn_off0_vs;
wire                   syn_off0_hs;
                       
wire                   off0_syn_de  ;
wire [VIDEO_WIDTH-1:0] off0_syn_data;

//-------------------------------------------------
wire        scl_vin_vs;  
wire        scl_vin_de;
wire [23:0] scl_vin_data;
            
wire        sclout_vs/*synthesis syn_keep=1*/  ;  
wire        sclout_de/*synthesis syn_keep=1*/  ;
wire [23:0] sclout_data/*synthesis syn_keep=1*/;

//------------------------------------------
//ADV7513 I2c
wire         TX_EN;
wire [2:0]   WADDR;
wire [7:0]   WDATA;
wire         RX_EN;
wire [2:0]   RADDR;
wire [7:0]   RDATA;

wire         error_flag;

//==============================================
//-------------------------------
assign O_led[0] = ~init_calib_complete;
assign O_led[1] = running;
assign O_led[2] = ~rst_n1;    
assign O_led[3] = ~I_rst_n;     


//==============================================
key_debounceN key_debounceN_inst0
(
	.clk       (I_clk), 
	.rst_n     (1'b1     ), 
	.key_in    (I_rst_n  ), 
	.key_n_out1(rst_n1   ),
	.key_n_out2(rst_n2   )
);

//===========================================================================
//------------------------------------------------------------------
//generate pixel clock
gw_pll gw_pll_inst
(
	.clkout (clkout        ), //output clkout 
	.lock   (pll_locked    ), //output lock
	.clkoutd(clkoutd       ),
	.reset  (!I_rst_n      ), //input reset
	.clkin  (I_clk     ) //input clkin
 );
 
 pix_pll pix_pll_inst
(
	.clkout (pixel_clk   ), //output clkout 
	.lock   (            ), //output lock
	.reset  (!I_rst_n    ), //input reset
	.clkin  (I_clk   ) //input clkin
 );
 
//===================================================
//LED灯测试
always @(posedge I_clk or negedge I_rst_n)
begin
	if(!I_rst_n)
		run_cnt <= 32'd0;
	else if(run_cnt >= 32'd50_000_000)
		run_cnt <= 32'd0;
	else
		run_cnt <= run_cnt + 1'b1;
end

assign  running = (run_cnt < 32'd25_000_000) ? 1'b1 : 1'b0;
 
 //-----------------------------------------------------
//实时参数选择
assign vin_hres		= 12'd1280    ;
assign vin_vres		= 12'd720     ;
assign vout_hres	= 12'd1920	  ;
assign vout_vres	= 12'd1080	  ;
assign hor_skfact	= 24'h00aaaa  ;
assign ver_skfact	= 24'h00aaaa  ;

//===========================================================================
//------------------------------------------------------------------
//测试图
reg         vs_r;
reg  [9:0]  cnt_vs;

testpattern testpattern_inst
(
	.I_pxl_clk   (clkoutd          ),//pixel clock
    .I_rst_n     (I_rst_n          ),//low active 
    .I_mode      ({1'b0,cnt_vs[9:8]}),//data select
    .I_single_r  (8'd0             ),
    .I_single_g  (8'd0             ),                  //40MHz      //65MHz      //74.25MHz   //148.5MHz 
    .I_single_b  (8'd255           ),                  //800x600    //1024x768   //1280x720   //1920x1080
    .I_h_total   (12'd1650         ),//hor total time  // 12'd1056  // 12'd1344  // 12'd1650  // 12'd2200
    .I_h_sync    (12'd40           ),//hor sync time   // 12'd128   // 12'd136   // 12'd40    // 12'd44  
    .I_h_bporch  (12'd220          ),//hor back porch  // 12'd88    // 12'd160   // 12'd220   // 12'd148 
    .I_h_res     (vin_hres         ),//hor resolution  // 12'd800   // 12'd1024  // 12'd1280  // 12'd1920
    .I_v_total   (12'd750          ),//ver total time  // 12'd628   // 12'd806   // 12'd750   // 12'd1125
    .I_v_sync    (12'd5            ),//ver sync time   // 12'd4     // 12'd6     // 12'd5     // 12'd5   
    .I_v_bporch  (12'd20           ),//ver back porch  // 12'd23    // 12'd29    // 12'd20    // 12'd36  
    .I_v_res     (vin_vres         ),//ver resolution  // 12'd600   // 12'd768   // 12'd720   // 12'd1080
    .I_hs_pol    (1'b1             ),//HS polarity , 0:负极性，1：正极性
    .I_vs_pol    (1'b1             ),//VS polarity , 0:负极性，1：正极性
    .O_de        (ch0_de_in        ),   
    .O_hs        (ch0_hs_in        ),
    .O_vs        (ch0_vs_in        ),
    .O_data_r    (ch0_data_r       ),   
    .O_data_g    (ch0_data_g       ),
    .O_data_b    (ch0_data_b       )
);

//------------------------------------
//控制测试图循环变化
always@(posedge clkoutd or negedge I_rst_n)
begin
	if(!I_rst_n)
		vs_r<=1'b0;
	else
		vs_r<=ch0_vs_in;
end

always@(posedge clkoutd or negedge I_rst_n)
begin
	if(!I_rst_n)
		cnt_vs<=10'd0;
	else if(vs_r && !ch0_vs_in) //vs falling edge
		cnt_vs<=cnt_vs+1'b1;
end

//============================================== 
`ifdef VIDEO_WIDTH_16    
	assign ch0_vfb_clk_in  = clkoutd;
	assign ch0_vfb_vs_in   = ~ch0_vs_in;
	assign ch0_vfb_de_in   = ch0_de_in;
	assign ch0_vfb_data_in = {ch0_data_b[7:3],ch0_data_g[7:2],ch0_data_r[7:3]};//{b,g,r}  RGB565
`endif

`ifdef VIDEO_WIDTH_24    
	assign ch0_vfb_clk_in  = clkoutd;
	assign ch0_vfb_vs_in   = ~ch0_vs_in;
	assign ch0_vfb_de_in   = ch0_de_in;
	assign ch0_vfb_data_in = {ch0_data_b,ch0_data_g,ch0_data_r};//{b,g,r}
`endif  
    
//=====================================================
//SRAM 控制模块 
vfb_top#
(
	.IMAGE_SIZE        (IMAGE_SIZE        ),     
	.BURST_WRITE_LENGTH(BURST_WRITE_LENGTH),
	.BURST_READ_LENGTH (BURST_READ_LENGTH ),
	.ADDR_WIDTH        (ADDR_WIDTH        ),
	.DATA_WIDTH        (DATA_WIDTH        ),
	.DQ_WIDTH          (DQ_WIDTH          ),
	.VIDEO_WIDTH       (VIDEO_WIDTH       )
)
vfb_top_inst
( 
	.I_rst_n		    (init_calib_complete ),//rst_n            ),
	.I_dma_clk		    (dma_clk          ),   //sram_clk         ),
	.I_wr_halt		    (1'd0             ), //1:halt,  0:no halt
	.I_rd_halt		    (1'd0             ), //1:halt,  0:no halt
	// video data input           
	.I_vin0_clk		    (ch0_vfb_clk_in   ),
	.I_vin0_vs_n	    (ch0_vfb_vs_in    ),
	.I_vin0_de		    (ch0_vfb_de_in    ),
	.I_vin0_data	    (ch0_vfb_data_in  ),
	// video data output          
	.I_vout0_clk	    (pixel_clk        ),
	.I_vout0_vs_n	    (~scl_vin_vs      ),
	.I_vout0_de		    (scl_vin_de       ),
	.O_vout0_den	    (off0_syn_de      ),
	.O_vout0_data	    (off0_syn_data    ),
	.O_vout0fifo_empty  (vout0fifo_empty  ),
	// ddr write request
	.cmd_ready          (cmd_ready          ),
	.cmd                (cmd                ),//0:write;  1:read
	.cmd_en             (cmd_en             ),
	.app_burst_number   (app_burst_number   ),
	.addr               (addr               ),//[ADDR_WIDTH-1:0]
	.wr_data_rdy        (wr_data_rdy        ),
	.wr_data_en         (wr_data_en         ),//
	.wr_data_end        (wr_data_end        ),//
	.wr_data            (wr_data            ),//[DATA_WIDTH-1:0]
	.wr_data_mask       (wr_data_mask       ),
	.rd_data_valid      (rd_data_valid      ),
	.rd_data_end        (rd_data_end        ),//unused 
	.rd_data            (rd_data            ),//[DATA_WIDTH-1:0]
	.init_calib_complete(init_calib_complete)
);  

//----------------------------------------------------- 
//ddr3 ip
DDR3_Memory_Interface_Top DDR3_Memory_Interface_Top_inst 
(
	.clk                (I_clk          ),
	.rst_n              (rst_n1             ),   //rst_n
	.app_burst_number   (app_burst_number   ),
	.cmd_ready          (cmd_ready          ),
	.cmd                (cmd                ),
	.cmd_en             (cmd_en             ),
	.addr               (addr               ),
	.wr_data_rdy        (wr_data_rdy        ),
	.wr_data            (wr_data            ),
	.wr_data_en         (wr_data_en         ),
	.wr_data_end        (wr_data_end        ),
	.wr_data_mask       (wr_data_mask       ),
	.rd_data            (rd_data            ),
	.rd_data_valid      (rd_data_valid      ),
	.rd_data_end        (rd_data_end        ),
	.sr_req             (                   ),
	.ref_req            (                   ),
	.sr_ack             (                   ),
	.ref_ack            (                   ),
	.init_calib_complete(init_calib_complete),
	.clk_out            (dma_clk            ),
	.burst              (1'b1               ),
	// mem interface
	.ddr_rst            (                   ),
	.O_ddr_addr         (O_ddr_addr         ),
	.O_ddr_ba           (O_ddr_ba           ),
	.O_ddr_cs_n         (                   ),
	.O_ddr_ras_n        (O_ddr_ras_n        ),
	.O_ddr_cas_n        (O_ddr_cas_n        ),
	.O_ddr_we_n         (O_ddr_we_n         ),
	.O_ddr_clk          (O_ddr_clk          ),
	.O_ddr_clk_n        (O_ddr_clk_n        ),
	.O_ddr_cke          (O_ddr_cke          ),
	.O_ddr_odt          (O_ddr_odt          ),
	.O_ddr_reset_n      (O_ddr_reset_n      ),
	.O_ddr_dqm          (O_ddr_dqm          ),
	.IO_ddr_dq          (IO_ddr_dq          ),
	.IO_ddr_dqs         (IO_ddr_dqs         ),
	.IO_ddr_dqs_n       (IO_ddr_dqs_n       )
);

//------------------------------------------------------
//Scaler
`ifdef VIDEO_WIDTH_16    
	assign scl_vin_data = {off0_syn_data[15:11],3'd0,off0_syn_data[10:5],2'd0,off0_syn_data[4:0],3'd0};//{b,g,r}  RGB565
`endif

`ifdef VIDEO_WIDTH_24    
	assign scl_vin_data = {{off0_syn_data[23:16],off0_syn_data[15:8],off0_syn_data[7:0]};//{b,g,r}
`endif  

assign scaler_clk = clkout;//clkout

Scaler_Top  Scaler_Top_inst
(
	.I_reset		(~I_rst_n			  ),//高有效
	.I_sysclk		(scaler_clk		      ),
`ifdef PARAM_DYNAMIC_CTRL
	.I_param_update	(1'b1        	      ),
	.I_vin_hsize	(vin_hres    		  ),
	.I_vin_vsize	(vin_vres    		  ),
	.I_vout_hsize	(vout_hres       	  ),
	.I_vout_vsize	(vout_vres       	  ),
	.I_hor_skfactor	(hor_skfact           ),
	.I_ver_skfactor	(ver_skfact           ),
`endif	
	.I_vin_clk		(pixel_clk	 	      ),
	.I_vin_ref_vs	(syn_off0_vs	      ),//正极性						  
	.I_vin_ref_de	(syn_off0_re	      ),
	.O_vin_vs_req	(scl_vin_vs		      ),//正极性					  
	.O_vin_de_req	(scl_vin_de		      ),
	.I_buff_ready   (~vout0fifo_empty     ),
	.I_up_down_sel	(1'b0       	      ),	
	.I_vin_de_cpl	(off0_syn_de		  ),					          
	.I_vin_data0_cpl(scl_vin_data[ 7: 0]  ), 
	.I_vin_data1_cpl(scl_vin_data[15: 8]  ), 
	.I_vin_data2_cpl(scl_vin_data[23:16]  ), 
	.O_vout0_data   (sclout_data[ 7: 0]   ),   		  
	.O_vout1_data   (sclout_data[15: 8]   ),   
	.O_vout2_data   (sclout_data[23:16]   ),   
	.I_vout_clk		(pixel_clk            ),								
	.O_vout_vs		(sclout_vs	          ),//正极性					   
	.O_vout_de		(sclout_de	          ) 
);	

//---------------------------------------------------
//输出同步时序模块
wire out_de;
syn_gen syn_gen_inst      //实际工程  pixel_clk时钟信号 从管脚输入， 可省去PLL
(                                   
    .I_pxl_clk   (pixel_clk       ),//40MHz      //65MHz      //74.25MHz   //148.5MHz  
    .I_rst_n     (I_rst_n         ),//800x600    //1024x768   //1280x720   //1920x1080 
    .I_h_total   (12'd2200        ),// 12'd1056  // 12'd1344  // 12'd1650  // 12'd2200 
    .I_h_sync    (12'd44          ),// 12'd128   // 12'd136   // 12'd40    // 12'd44   
    .I_h_bporch  (12'd148         ),// 12'd88    // 12'd160   // 12'd220   // 12'd148  
    .I_h_res     (12'd1920        ),// 12'd800   // 12'd1024  // 12'd1280  // 12'd1920 
    .I_v_total   (12'd1125        ),// 12'd628   // 12'd806   // 12'd750   // 12'd1125 
    .I_v_sync    (12'd5           ),// 12'd4     // 12'd6     // 12'd5     // 12'd5    
    .I_v_bporch  (12'd36          ),// 12'd23    // 12'd29    // 12'd20    // 12'd36   
    .I_v_res     (12'd1080        ),// 12'd600   // 12'd768   // 12'd720   // 12'd1080 
    .I_rd_hres   (vout_hres       ),
    .I_rd_vres   (vout_vres       ),
    .I_hs_pol    (1'b1            ),//HS polarity , 0:负极性，1：正极性
    .I_vs_pol    (1'b1            ),//VS polarity , 0:负极性，1：正极性
    .O_rden      (syn_off0_re     ),
    .O_de        (out_de          ),   
    .O_hs        (syn_off0_hs     ),
    .O_vs        (syn_off0_vs     )
);

//--------------------------------------------------
`ifdef VIDEO_WIDTH_16
	assign O_adv7513_clk  = pixel_clk;
	assign O_adv7513_vs   = sclout_vs;
	assign O_adv7513_hs   = syn_off0_hs;
	assign O_adv7513_de   = sclout_de;
	assign O_adv7513_data = {sclout_data[7:0],sclout_data[15:8],sclout_data[23:16]};//{r,g,b}
`endif

`ifdef VIDEO_WIDTH_24
	assign O_adv7513_clk  = pixel_clk;
	assign O_adv7513_vs   = sclout_vs;
	assign O_adv7513_hs   = syn_off0_hs;
	assign O_adv7513_de   = sclout_de;
	assign O_adv7513_data = {sclout_data[7:0],sclout_data[15:8],sclout_data[23:16]};//{r,g,b}
`endif

//=========================================================================
// ADV7513 I2c 初始化
adv7513_iic_init adv7513_iic_init_inst
(
	.I_CLK              ( I_clk             ),
	.I_RESETN           ( rst_n1                ),
	.start              ( rst_n2                ),
	.O_TX_EN            ( TX_EN                 ),
	.O_WADDR            ( WADDR                 ),
	.O_WDATA            ( WDATA                 ),
	.O_RX_EN            ( RX_EN                 ),
	.O_RADDR            ( RADDR                 ),
	.I_RDATA            ( RDATA                 ),
	.cstate_flag        (                       ),
	.error_flag         (error_flag             )
);

I2C_MASTER_Top I2C_MASTER_Top_inst
(
	.I_CLK              ( I_clk             ),
	.I_RESETN           ( rst_n1                ),
	.I_TX_EN            ( TX_EN                 ),
	.I_WADDR            ( WADDR                 ),
	.I_WDATA            ( WDATA                 ),
	.I_RX_EN            ( RX_EN                 ),
	.I_RADDR            ( RADDR                 ),
	.O_RDATA            ( RDATA                 ),
	.O_IIC_INT          (                       ),
	.SCL                ( IO_adv7513_scl        ),
	.SDA                ( IO_adv7513_sda        )
); 

endmodule