// --------------------------------------------------------------------
//   ==================================================================
//   >>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<
//   ------------------------------------------------------------------
//   Copyright (c) 2014 by Lattice Semiconductor Corporation
//   ALL RIGHTS RESERVED 
//   ------------------------------------------------------------------
//
//   Permission:
//
//      Lattice SG Pte. Ltd. grants permission to use this code
//      pursuant to the terms of the Lattice Reference Design License Agreement. 
//
//
//   Disclaimer:
//
//      This VHDL or Verilog source code is intended as a design reference
//      which illustrates how these types of functions can be implemented.
//      It is the user's responsibility to verify their design for
//      consistency and functionality through the use of formal
//      verification methods.  Lattice provides no warranty
//      regarding the use or functionality of this code.
//
//   --------------------------------------------------------------------
//
//                  Lattice SG Pte. Ltd.
//                  101 Thomson Road, United Square #07-02 
//                  Singapore 307591
//
//
//                  TEL: 1-800-Lattice (USA and Canada)
//                       +65-6631-2000 (Singapore)
//                       +1-503-268-8001 (other locations)
//
//                  web: http://www.latticesemi.com/
//                  email: techsupport@latticesemi.com
//
//   --------------------------------------------------------------------
//
// This is the test bench module of the Sony_sensor_bridge design.  
// 
// --------------------------------------------------------------------
//
// Revision History :
// --------------------------------------------------------------------
//   Ver  :| Author            :| Mod. Date :| Changes Made:
//   V0.1 :|           		   :| 06/29/09  :| Pre-Release
//   V0.2 :| Srikanth          :| 03/01/14  :| Added self checking 
// --------------------------------------------------------------------

`timescale 1ns / 10ps

module mipi_csi2_tb();	 
/////////////////////////////////////////////////////////////
   parameter word_width        = 10   ;
   parameter lane_width        = 2    ;
/////////////////////////////////////////////////////////////   
   GSR GSR_INST(.GSR(1'b1));
   PUR PUR_INST(.PUR(1'b1));	 
   parameter num_frames        = 10  ;
   parameter htotal            = 2200/lane_width ;
   parameter hactive           = 1920/lane_width ;
   parameter htotal_8bit       = (word_width*htotal) /8 ; 
   parameter hactive_8bit      = (word_width*hactive)/8 ;
   parameter vtotal            = 1125;
   parameter vactive           = 1080;   


   reg                      rstn           ;
   reg                      clk            ;
   reg                      clkx2          ; 
   reg                      clkx4          ;
   reg                      clkx8          ;
   reg                      clkx16         ;
   reg  [15:0] data_in;
   reg  [7:0]  data0, data1, d0;
   reg  dout, dout1;
   reg  [2:0] data_cntr; 
   reg  hactive_flag;
   wire [9:0] pixdata;
   
   initial begin                       
      rstn       = 1'b0;          
      clk        = 1'b0; clkx2       = 1'b0; clkx4       = 1'b0; clkx8       = 1'b0;  clkx16       = 1'b0;
      data_in    = 'b0; d0 =1'b0; 
      data_cntr  = 'b0;
	  hactive_flag = 'b0;
      #1200 rstn = 1'b1; 
      #200; 
       repeat (num_frames) begin  
	       //FS - Frame Start
		   repeat (1) begin
            @(negedge clkx2) data_in = 'h1D1D; // Leader Sequence = 00011101,
            @(negedge clkx2) data_in = 'h0000; // Data ID = {VC = 1, Frame Start Code = 0},
            @(negedge clkx2) data_in = 'h00AA; // short packet data =channel 0, ECC=10101010
			  repeat(htotal_8bit-3)
			      @(negedge clkx2) data_in = 'h0000; 
	       end
		   //Active region
		   repeat (vactive) begin
           //Packet Header 
            @(negedge clkx2) data_in = 'h1D1D; // Leader Sequence = 00011101,
            @(negedge clkx2) data_in = 'h06D4; // Data ID = {VC = 0, Device Type = 0x2B = Raw10},
            @(negedge clkx2) begin data_in = 'hB890; hactive_flag = 1; end// ECC=1D
           //line data 1,2,3,...
            //@(negedge clkx2) begin data_in = 'h0101;  end
            repeat(hactive_8bit)
               @(negedge clkx2) begin data_in = {data0, data1}; end  
        //Packet Footer
        @(negedge clkx2) begin data_in = 'hCEEC; hactive_flag = 0; end	//checksum = 0xCEEC 
        @(negedge clkx2) data_in = 'hCEEC;	//checksum = 0xCEEC	
			  //Blanking
			  repeat(htotal_8bit-hactive_8bit-3-2) //blanking = total - active - PH - PF
			      @(negedge clkx2) data_in = 0;	
	       end
		   //FE - Frame End
		   repeat (1) begin
            @(negedge clkx2) data_in = 'h1D1D; // Leader Sequence = 00011101,
	          @(negedge clkx2) data_in = 'h0001; // Data ID = {VC = 1, Frame End Code = 1},
		        @(negedge clkx2) data_in = 'h00AA; // Short Packet Data = channel 0, ECC=10101010		 
			  repeat(htotal_8bit-3)
			      @(negedge clkx2) data_in = 'h0000; 
           end 
   		   //vertical blanking 
		   repeat (vtotal-vactive-1-1) begin  //blanking = total - active - FS - FE	
			   repeat(htotal_8bit)
            @(negedge clkx2) data_in = 'h0000;
		   end
       end
   end
   
   parameter periode_16    = 1 ;  
   parameter periode_8     = 2 ;
   parameter periode_4     = 4 ;
   parameter periode_2     = 8 ; 
   parameter periode_1     = 16;  
   always clk    = #periode_1  ~clk;                                      
   always clkx2  = #periode_2  ~clkx2; 
   always clkx4  = #periode_4  ~clkx4;            
   always clkx8  = #periode_8  ~clkx8;
   always clkx16 = #periode_16 ~clkx16;
   
   always @(posedge clkx4 or negedge rstn) begin
       if(~hactive_flag)   begin
		 data0 <= 0;
		 data1 <= 0; 
		 d0    <= 0;
		 data_cntr <= 0;
	   end
	   else	 begin
         data0     <= (data_cntr==4) ? 8'h27 : {d0[0],d0[1],d0[2],d0[3],d0[4],d0[5],d0[6],d0[7]};
		 data1     <= data0;
		 d0        <= d0 + (data_cntr==4); 
		 data_cntr <= (data_cntr<4) ? data_cntr+1 : 0;
	   end
   end
	   
	   
integer i;
   always @(posedge clkx16 or negedge rstn) begin
       if(~rstn)
          i <= 7;
       else if (i>0)
          i <= i-1;
       else
		  i <=7;
   end	
   always @(posedge clkx16 or negedge rstn) begin
       if(~rstn) begin
		 dout  <= 0;
		 dout1 <= 0;	
	   end	 
	   else	begin
         dout  <= data_in[i];  	
		 dout1 <= data_in[i+8];	 
	   end
   end

   MIPI_CSI2_Serial2Parallel_Bridge  #(
      .bus_width         (word_width    ),
      .lane_width        (lane_width    ))   
   mipi_bridge(                 
      .rstn              ( rstn ),
      .DCK               ( clkx8),   // serial clock
      .CH0               ( dout ),
      .CH1               ( dout1 ),
      .CH2               (       ),
      .CH3               (      ),   // LVDS DDR input data
      .pixclk_adj        (pixclk),   
      .pixdata           (pixdata),   
      .fv                (  fv  ),   
      .lv                (  lv  ),
	  .sensor_clk  		 ( clkx8)
   );		
		
//******************************************************************************************
/////////////////////              SELF CHECKING PART           ////////////////////////////
//******************************************************************************************		
	//integer file, r, a, b;	
	wire empty0,empty1,rd_en;
	wire [1:0] flag;
	reg q_lv,x;
	reg [9:0] pixdata_in,q1_pixdata_in;
	wire [9:0] pixdata_out,pixdata_expected;
	//wire [9:0] pixdata_in2;
		


    //////////EXPECTED DATA GENERATION LOGIC/////////////		
	always @ ( posedge pixclk or negedge rstn) 	begin
       if(~rstn) begin
		 
		 q_lv <= 0;	
		 q1_pixdata_in <= 0; 
		 x <=0;
		 pixdata_in  <= 0;
	   end	 
	   else	begin
       
		 q_lv <= lv;
		 `ifdef tim_sim
		 pixdata_in <= (x & lv)? q1_pixdata_in:pixdata_in;
		 `else		 
		  pixdata_in <= (lv) ? pixdata_in+1:0;  
		 `endif	  
		 
		 q1_pixdata_in <= (/*q_lv & */ lv ) ? q1_pixdata_in+1:0;
		 x<=1;
	   end
   end
	
	
	assign rd_en = (~empty0) & (~empty1);
	

	////////////////MONITOR OR RECEIVER LOGIC//////////////////
	
	
	simulation_fifo_10bit_to_10bit u_simulation_fifo_input(.Data(pixdata_in), .WrClock(pixclk), .RdClock(pixclk), .WrEn(lv), .RdEn(rd_en), .Reset(~rstn), .RPReset(~rstn), .Q(pixdata_expected), .AlmostFull(), .Empty(empty0));	
		
	simulation_fifo_10bit_to_10bit u_simulation_fifo_output(.Data(pixdata), .WrClock(pixclk), .RdClock(pixclk), .WrEn(lv), .RdEn(rd_en), .Reset(~rstn), .RPReset(~rstn), .Q(pixdata_out), .AlmostFull(), .Empty(empty1));	
		
		
		
		
	////////// COMPARISSION LOGIC//////////////////	
	
         	
		assign	flag  = (!rd_en)? 2'b00: (pixdata_out==pixdata_expected)?2'b11:2'b10;  		

     
	
    //////////// SCORE BOARD/////////////////////////
	
		always @ ( posedge pixclk or negedge rstn) 	begin
       if(~rstn) 
		 $display (" IN RESET MODE ");
	   else	if(flag==2'b00)
	        $display("BLANKING PERIOD");
			else
	           if (flag==2'b11)
		         $display("OUTPUT DATA MATCHES WITH THE EXPECTED DATA AS %h", pixdata_out );
			   else	if(flag==2'b10)
				   begin
			        $display("XXXXXXXXXXX DATA MISMATCH XXXXXXXXXXX");
					$finish;
				 end
         	
        end
				
		
endmodule                                  