//simple testbench for fast simulation only
`timescale 100ps/100ps
module hispi_rx_top_tb;

parameter pmi_family     = "XO2";          //"ECP3" or "XP2"
parameter c_HDR_MODE     = "false";          //"true" or "false"
parameter c_HISPI_MODE   = "Packetized-SP"; //"Packetized-SP" or "Streaming-SP" or "Streaming-S" or "ActiveStart-SP8"
parameter c_WORD_WIDTH   = 12;              //10/12/14/16/20
parameter c_LANE_WIDTH   = 2;                //LANE NUMBER 1/2/3/4             

parameter c_PER_LANE_WIDTH = (c_LANE_WIDTH > 2) ? 10 : c_WORD_WIDTH; //for c_HDR_MODE = "true" only

wire [13-1:0] pix_per_ln;
reg  rstn;
reg rst_stim_n;
reg  sclk;
wire sclk_i;
wire [3:0] sdin_i;
wire sclk_i_hdr;
wire [3:0] sdin_i_hdr;
wire sclk_i_normal;
wire [3:0] sdin_i_normal;
wire [c_WORD_WIDTH-1:0] dout;
reg clk_i;
wire sdr_clk, sdr_CSn, sdr_WEn, sdr_RASn,sdr_CKE,sdr_CASn;
wire [1:0] sdr_DQM;
wire [1:0] sdr_BA;
wire [11:0] sdr_A;
wire [15:0] sdr_DQ;	
reg sclk_o;		
integer clk_cnt;

initial begin
   rstn = 0;
   sclk = 0;
   clk_i= 0;  
   #110;
   rstn = 1;
end

always #10 sclk = ~sclk;
always #1  clk_i= ~clk_i;	

always @(negedge sclk or negedge rstn)
   if (!rstn) begin
      sclk_o       <= 0;  
	  rst_stim_n <= 0; 
	  clk_cnt <=0;
   end
   else begin
      sclk_o       <= ~ sclk_o;	 
	  if(clk_cnt==20000)
	  	rst_stim_n <= 1;
	  clk_cnt<=clk_cnt+1;
   end
   
wire [13-1:0] vd_active_width = 'd644;
wire [13-1:0] pix_per_ln_sp = (vd_active_width - 4) * c_LANE_WIDTH;
wire [13-1:0] pix_per_ln_s = (c_LANE_WIDTH == 4) ? ((vd_active_width - 1) * 4) : ((c_LANE_WIDTH == 2) ? ((vd_active_width - 2) * 2) : (vd_active_width - 4));
wire [13-1:0] pix_per_ln_sp8 = (vd_active_width - 8) * c_LANE_WIDTH;
assign pix_per_ln = (c_HISPI_MODE == "Packetized-SP") ? 'd0 : (
                    (c_HISPI_MODE == "Streaming-SP") ? pix_per_ln_sp : (
                                                       (c_HISPI_MODE == "Streaming-S") ? pix_per_ln_s : pix_per_ln_sp8
                                                       )
                    );

XP2_HiSPI2Parallel_I2C_top #(
.pmi_family     (pmi_family       ), //"ECP3" or "XP2"
.c_HDR_MODE     (c_HDR_MODE       ), //"true" or "false"
.c_HISPI_MODE   (c_HISPI_MODE     ), //"Packetized-SP" or "Streaming-SP" or "Streaming-S" or "ActiveStart-SP8"
.c_WORD_WIDTH   (c_WORD_WIDTH     ), //10/12/14/16/20
.c_LANE_WIDTH   (c_LANE_WIDTH     )  //LANE NUMBER 1/2/3/4
)
I_hispi_top(
	.clk_i			 (clk_i),
	.reset_n         (rstn             ),
	//hispi input port
	.hispi_clk        (sclk_o           ),
	.hispi_data       ({2'b00,sdin_i[1:0]}),
	.hispi_clk_s2     (sclk_o           ),
	.hispi_data_s2    ({2'b00,sdin_i[3:2]}),
	.hispi_resetn	  (),

	//output port
	.hispi_sens_clk   (pclk             ),
	.hispi_sens_fv    (f_valid          ),	
	.hispi_sens_lv    (l_valid          ),
	.hispi_sens_data  (dout             ),

   // I2C
   .sda_sensor(),
   .scl_sensor(),
   .sda_sensor_s1(),
   .scl_sensor_s1(),
   .sda_sensor_s2(),
   .scl_sensor_s2(),

   // Sensor Inputs
	.saddr(),
	.trigger(),
	.output_en_n(),
	.standby(),
	.XO2_clk(),
	.LED_S1(),
	
	.sensor_switch(1'b1),
	
	// SDR
	.sdr_DQ(sdr_DQ),        // sdr data
	.sdr_A(sdr_A),         	// sdr address
	.sdr_BA(sdr_BA),        // sdr bank address
	.sdr_CKE(sdr_CKE),       		// sdr clock enable
	.sdr_CSn(sdr_CSn),      // sdr chip select
	.sdr_RASn(sdr_RASn), 	// sdr row address
	.sdr_CASn(sdr_CASn),     		// sdr column select
	.sdr_WEn(sdr_WEn),      // sdr write enable
	.sdr_DQM(sdr_DQM),				// sdr write data mask
	.sdr_clk(sdr_clk)
); 

//RamChip U2(.Address({sdr_BA,sdr_A}), .Data(sdr_DQ), .CLK(sdr_clk), .CS(~sdr_RASn), .WE(sdr_WEn));	  
mt48lc4m16a2 U2 (.Dq(sdr_DQ), .Addr(sdr_A), .Ba(sdr_BA), .Clk(sdr_clk), .Cke(sdr_CKE), .Cs_n(sdr_CSn), .Ras_n(sdr_RASn), .Cas_n(sdr_CASn), .We_n(sdr_WEn), .Dqm(sdr_DQM));

hispi_hdr_stim #(
.c_PER_LANE_WIDTH (c_PER_LANE_WIDTH),
.c_WORD_WIDTH     (c_WORD_WIDTH ),
.c_LANE_WIDTH     (c_LANE_WIDTH )
)
I_hispi_hdr_stim(
 .vd_active_width     (12'd644),  //AIL length = vd_active_width(1280) + sync width(4)
 .vd_blank_width      (12'd90),
 .vd_active_height    (12'd12),
 .vd_blank_height     (12'd15),
 .ail_msb_1st         (1'b0),
 .rstn                (rstn),
 .sclk                (sclk),
 .sclk_o              (sclk_i_hdr),
 .sdata_o             (sdin_i_hdr)
);

hispi_stim #(
.c_HISPI_MODE   (c_HISPI_MODE ),//"Packetized-SP" or "Streaming-SP" or "Streaming-S" or "ActiveStart-SP8"
.c_WORD_WIDTH   (c_WORD_WIDTH ),
.c_LANE_WIDTH   (4 )
)
I_hispi_stim(
 .vd_active_width     (12'd644),  //AIL length = vd_active_width + sync width
 .vd_blank_width      (12'd90),
 .vd_active_height    (12'd12),
 .vd_blank_height     (12'd15),

 .rstn                (rstn/*rst_stim_n*/),
 .sclk                (sclk),
 .sclk_o              (sclk_i_normal),
 .sdata_o             (sdin_i_normal)
);   

assign sclk_i = (c_HDR_MODE == "true") ? sclk_i_hdr : sclk_i_normal;
assign sdin_i = (c_HDR_MODE == "true") ? sdin_i_hdr : sdin_i_normal;

generate                          
   if (c_HDR_MODE == "true") begin
//*****************************************************************************************************

reg [20-1:0] expected_data;
reg error;
always @(posedge pclk or negedge rstn)
   if (!rstn) begin
      expected_data <= 0;
   end
   else begin
      if (f_valid) begin
         if (l_valid)
            expected_data <= expected_data + 1;
      end
      else begin
         expected_data <= 0;
      end
   end

wire [9:0] data_pattern_lane_0 = {expected_data[19], expected_data[17], expected_data[15], expected_data[13], expected_data[11],
                                  expected_data[9],  expected_data[7],  expected_data[5],  expected_data[3],  expected_data[1]};
wire [9:0] data_pattern_lane_1 = {expected_data[18], expected_data[16], expected_data[14], expected_data[12], expected_data[10],
                                  expected_data[8],  expected_data[6],  expected_data[4],  expected_data[2],  expected_data[0]};
                                  
wire [9:0] data_pattern_lane_0_tmp = data_pattern_lane_0 == 0 ? 10'd1 : data_pattern_lane_0;
wire [9:0] data_pattern_lane_1_tmp = data_pattern_lane_1 == 0 ? 10'd1 : data_pattern_lane_1;
wire [20-1:0] expected_data_tmp_20b = {data_pattern_lane_0_tmp[9], data_pattern_lane_1_tmp[9], data_pattern_lane_0_tmp[8], data_pattern_lane_1_tmp[8],
                                    data_pattern_lane_0_tmp[7], data_pattern_lane_1_tmp[7], data_pattern_lane_0_tmp[6], data_pattern_lane_1_tmp[6],
                                    data_pattern_lane_0_tmp[5], data_pattern_lane_1_tmp[5], data_pattern_lane_0_tmp[4], data_pattern_lane_1_tmp[4],
                                    data_pattern_lane_0_tmp[3], data_pattern_lane_1_tmp[3], data_pattern_lane_0_tmp[2], data_pattern_lane_1_tmp[2],
                                    data_pattern_lane_0_tmp[1], data_pattern_lane_1_tmp[1], data_pattern_lane_0_tmp[0], data_pattern_lane_1_tmp[0]};
                                    
wire [c_WORD_WIDTH-1:0] expected_data_tmp_2lanes = (expected_data[c_WORD_WIDTH-1:0] == 0) ? 1 : expected_data[c_WORD_WIDTH-1:0];

wire [20-1:0] expected_data_tmp = (c_WORD_WIDTH == 20) ? expected_data_tmp_20b : ((c_LANE_WIDTH == 2) ? expected_data_tmp_2lanes : expected_data);
always @(posedge pclk or negedge rstn)
   if (!rstn) begin
      error <= 1'b0;
   end
   else begin
      if (l_valid)
         error <= {expected_data_tmp[c_WORD_WIDTH-1:0]} != dout;
   end

//*****************************************************************************************************
   end
   else if (c_HDR_MODE == "false") begin
//*****************************************************************************************************


reg [1:0] word_cnt;
reg [c_WORD_WIDTH-3:0] expected_data;
reg error;
always @(posedge pclk or negedge rstn)
   if (!rstn) begin
      word_cnt <= 0;
      expected_data <= 0;
   end
   else begin
      if (f_valid) begin
         if (l_valid) begin
            if (word_cnt == c_LANE_WIDTH - 1) begin
               word_cnt <= 0;
               expected_data <= expected_data + 1;
            end
            else
               word_cnt <= word_cnt + 1;
         end
      end
      else begin
         expected_data <= 0;
         word_cnt      <= 0;
      end
   end              
wire [c_WORD_WIDTH-3:0] expected_data_tmp = (& expected_data) ? {expected_data[c_WORD_WIDTH-3:1], 1'b0} : ((| expected_data) ? expected_data : {expected_data[c_WORD_WIDTH-3:1], 1'b1});

always @(posedge pclk or negedge rstn)
   if (!rstn) begin
      error <= 1'b0;
   end
   else begin
      if (l_valid)
         error <= {expected_data_tmp, word_cnt} != dout;
   end
//*****************************************************************************************************
   end
endgenerate





GSR GSR_INST(1'b1);
PUR PUR_INST(1'b1);

//

endmodule
