`include "../../rtl/define/chip_define.v"

`include "../../model/SPI_DRIVER.sv"

`include "../../model/LVDS_DRIVER.sv"

`timescale 1ns/1ps

module TB ();

//###################################
// Generate Clocks & Reset
//###################################

//Generate Clock
localparam PERIOD  = 1.536;
logic clk      ;
//clk  
clock_tb          #(
   .PERIOD         ( PERIOD   ) 
  ,.PHASE          ( 0        )
  )clk_inst        (          
   .clk_out        ( clk      )
);

//clk_40g
logic clk_40g;
clock_tb          #(
   .PERIOD         ( 0.024) 
  ,.PHASE          ( 0        )
  )clk_40g_inst    (          
   .clk_out        ( clk_40g  )
);
//Generate Reset
logic rst_n;

int file_path;
string CONFIG_FILE = "";
string DATA_O_FILE = "";
parameter string CASE_TEMP = "../../case_temp.txt";
parameter string DATA_TEMP = "../../data_temp.txt"; 
parameter string LVDS_FILE = "../../../../case/lvds/0305/lvds.txt";
initial begin
  file_path = $fopen(CASE_TEMP, "r");
  if(file_path != 0) begin
    $fscanf(file_path, "%s", CONFIG_FILE);
    $display(CONFIG_FILE);
    $fclose(file_path);
  end
  file_path = $fopen(DATA_TEMP, "r");
  if(file_path != 0) begin
    $fscanf(file_path, "%s", DATA_O_FILE);
    $display(DATA_O_FILE);
    $fclose(file_path);
  end

  $fsdbAutoSwitchDumpfile(500, "./verdplus.fsdb", 1000000);
  $fsdbDumpvars();
  $fsdbDumpMDA();
end 

//###################################
// configure the dut
//################################### 
virtual spi_if vif;
spi_if spi_bus(.clk(clk), .rstn(rst_n));

virtual lvds_if lvds_vif;
lvds_if lvds_bus(.clk(clk));



initial begin
  spi_bus.sclk = 1'b1;
  spi_bus.mosi = 1'b0;
  spi_bus.csn  = 1'b1;
  vif          = spi_bus;
  lvds_vif     = lvds_bus;
end

spi_driver my_drv;
lvds_driver lvds_drv;
logic start;

initial begin
  rst_n = 1'b0;
  start = 1'b0;

  lvds_drv = new();
  //lvds_drv.file_path = LVDS_FILE;
  lvds_drv.drv_if = lvds_vif;


  my_drv = new();
  my_drv.file_path = CONFIG_FILE;
  my_drv.itf = vif;

  # 20;
  rst_n = 1'b1;
  
  //lvds_drv.do_drive();
  lvds_drv.train_count = 100;  //                         
  lvds_drv.send_training();   //                         
  lvds_drv.scrambler_en = 1; 
  lvds_drv.send_frame_from_file(LVDS_FILE);  //                     

  file_path = $fopen(DATA_O_FILE, "w");
  my_drv.do_drive(file_path);
  $fclose(file_path);

  # 30;
  start = 1'b1;
  # PERIOD;
  # PERIOD;
  start = 1'b0;
  
  # 30000;

  file_path = $fopen(DATA_O_FILE, "w");
  my_drv.do_drive(file_path);
  $fclose(file_path);

  start = 1'b1;
  # PERIOD;
  # PERIOD;
  start = 1'b0;

  # 30000;

  file_path = $fopen(DATA_O_FILE, "w");
  my_drv.do_drive(file_path);
  $fclose(file_path);

  start = 1'b1;
  # PERIOD;
  # PERIOD;
  start = 1'b0;

  # 30000;
  
  start = 1'b1;
  # PERIOD;
  # PERIOD;
  start = 1'b0;
  # 30000;

  $finish(0);
end

////////////////////////////////////////////////////////////////////////////////////////
//DUT
//////////////////////////////////////////////////////////////////////////////////////// 
 
//sync_out
logic          sync_out      ; 
//irq
logic          irq           ;
//lvds rx
logic  [3  :0] lvds_data     = '0; 
logic  [0  :0] lvds_valid    = '0; 
logic  [0  :0] lvds_clk      = '0; 
//DAC Data                   
logic [6  :0] MSB_OUT [63:0] ;
logic [4  :0] LSB_OUT [63:0] ;
logic             MSB_DUM [63:0] ;
logic             DEM_VLD        ;
//DAC Cfg Port               
logic [3  :0] Rterm          ; 
logic [2  :0] CasAddr        ;
logic [2  :0] CasDw          ;
logic [9  :0] IMainCtrl      ;
logic [3  :0] IBleedCtrl     ;
logic [3  :0] ICkCml         ;
logic [31 :0] CurRsv0        ;
logic [31 :0] CurRsv1        ;
//CLK Cfg Port               
logic [0  :0] CcalRstn       ;
logic [3  :0] EnAllP         ;
logic [0  :0] DccEn          ;
logic [0  :0] CasGateCkCtrl  ;
logic [0  :0] SpiEnPi        ;
logic [0  :0] SpiEnQec       ;
logic [0  :0] SpiEnDcc       ;
logic [4  :0] SpiQecCtrlIp   ;
logic [4  :0] SpiQecCtrlIn   ;
logic [4  :0] SpiQecCtrlQp   ;
logic [4  :0] SpiQecCtrlQn   ;
logic [5  :0] SpiDccCtrlIup  ;
logic [5  :0] SpiDccCtrlIdn  ;
logic [5  :0] SpiDccCtrlQup  ;
logic [5  :0] SpiDccCtrlQdn  ;
logic [7  :0] SpiSiqNOut     ;
logic [7  :0] SpiSiqPOut     ;
logic [3  :0] SpiSiPOut      ;
logic [3  :0] SpiSqPOut      ;
logic [2  :0] CrtlCrossOverN ;
logic [2  :0] CrtlCrossOverP ;
logic [31 :0] CcalRsv0       ;
logic [31 :0] CcalRsv1       ;
logic [3  :0] SelCk10GDig    ;
logic [3  :0] SelCk2p5GDig   ;
logic [8  :0] SelCk625MDig   ;
logic [15 :0] P2sDataEn      ;
logic [15 :0] P2sEnAllP      ;
logic [15 :0] EnPiP          ;
logic [15 :0] CkDivRstn      ;
logic [31 :0] p2srsv0        ;
logic [31 :0] p2srsv1        ;
logic [15 :0] CkRxSw         ;
logic [15 :0] RstnCk         ;
logic [15 :0] CtrlZin        ;
  
  
da4008_chip_top U_da4008_chip_top (            
   .PI_sclk                       ( spi_bus.sclk                   )          
  ,.PI_csn                        ( spi_bus.csn                    )
  ,.PI_mosi                       ( spi_bus.mosi                   )
  ,.PO_miso                       ( spi_bus.miso                   )
  ,.PO_irq                        ( irq                            )
  ,.PI_async_rstn                 ( rst_n                          )
  ,.PI_sync_in                    ( start                          )
  ,.PO_sync_out                   ( sync_out                       )                               
  ,.clk                           ( clk                            )
  ,.lvds_data                     ( lvds_bus.data                  )
  ,.lvds_valid                    ( lvds_bus.valid                 )
  ,.lvds_clk                      ( lvds_bus.clk                   )
  ,.MSB_OUT                       ( MSB_OUT                        )
  ,.LSB_OUT                       ( LSB_OUT                        )
  ,.MSB_DUM                       ( MSB_DUM                        )
  ,.DEM_VLD                       ( DEM_VLD                        )
  ,.Rterm                         ( Rterm                          )
  ,.CasAddr                       ( CasAddr                        )
  ,.CasDw                         ( CasDw                          )
  ,.IMainCtrl                     ( IMainCtrl                      )
  ,.IBleedCtrl                    ( IBleedCtrl                     )
  ,.ICkCml                        ( ICkCml                         )
  ,.CurRsv0                       ( CurRsv0                        )
  ,.CurRsv1                       ( CurRsv1                        )
  ,.CcalRstn                      ( CcalRstn                       )
  ,.EnAllP                        ( EnAllP                         )
  ,.DccEn                         ( DccEn                          )
  ,.CasGateCkCtrl                 ( CasGateCkCtrl                  )
  ,.SpiEnPi                       ( SpiEnPi                        )
  ,.SpiEnQec                      ( SpiEnQec                       )
  ,.SpiEnDcc                      ( SpiEnDcc                       )
  ,.SpiQecCtrlIp                  ( SpiQecCtrlIp                   )
  ,.SpiQecCtrlIn                  ( SpiQecCtrlIn                   )
  ,.SpiQecCtrlQp                  ( SpiQecCtrlQp                   )
  ,.SpiQecCtrlQn                  ( SpiQecCtrlQn                   )
  ,.SpiDccCtrlIup                 ( SpiDccCtrlIup                  )
  ,.SpiDccCtrlIdn                 ( SpiDccCtrlIdn                  )
  ,.SpiDccCtrlQup                 ( SpiDccCtrlQup                  )
  ,.SpiDccCtrlQdn                 ( SpiDccCtrlQdn                  )
  ,.SpiSiqNOut                    ( SpiSiqNOut                     )
  ,.SpiSiqPOut                    ( SpiSiqPOut                     )
  ,.SpiSiPOut                     ( SpiSiPOut                      )
  ,.SpiSqPOut                     ( SpiSqPOut                      )
  ,.CrtlCrossOverN                ( CrtlCrossOverN                 )
  ,.CrtlCrossOverP                ( CrtlCrossOverP                 )
  ,.CcalRsv0                      ( CcalRsv0                       )
  ,.CcalRsv1                      ( CcalRsv1                       )
  ,.SelCk10GDig                   ( SelCk10GDig                    )
  ,.SelCk2p5GDig                  ( SelCk2p5GDig                   )
  ,.SelCk625MDig                  ( SelCk625MDig                   )
  ,.P2sDataEn                     ( P2sDataEn                      )
  ,.P2sEnAllP                     ( P2sEnAllP                      )
  ,.EnPiP                         ( EnPiP                          )
  ,.CkDivRstn                     ( CkDivRstn                      )
  ,.p2srsv0                       ( p2srsv0                        )
  ,.p2srsv1                       ( p2srsv1                        )
  ,.CkRxSw                        ( CkRxSw                         )
  ,.RstnCk                        ( RstnCk                         )
  ,.CtrlZin                       ( CtrlZin                        )
); 

////////////////////////////////////////////////////////////////////////////////////////
//DEM_Reverse_64CH
//////////////////////////////////////////////////////////////////////////////////////// 

logic             vld_out         ;
logic [7  :0] data_out [63:0] ;

DEM_Reverse_64CH U_DEM_Reverse_64CH (
   .clk                             ( clk                            )
  ,.msb_in                          ( MSB_OUT                        )
  ,.lsb_in                          ( LSB_OUT                        )
  ,.vld_in                          ( DEM_VLD                        )
  ,.vld_out                         ( vld_out                        )
  ,.data_out                        ( data_out                       )
);  

logic [7  :0] data_out_r [63:0] ; 
logic         vld_out_r         ;

always @(posedge clk_40g) begin
  data_out_r <= data_out ;
  vld_out_r  <= vld_out  ;
end 
///////////////////////////////////////////////////////////////////////
//DA4008 DEM output data save
///////////////////////////////////////////////////////////////////////

wire add_cnt = vld_out_r;
wire end_cnt = 1'b0;

logic [5 :0] cnt_c; 
wire  [5 :0] cnt_n = end_cnt ? 6'h0         :
                     add_cnt ? cnt_c + 1'b1 :
                     cnt_c                  ;
                                        
always @(posedge clk_40g or negedge rst_n) begin
  if(rst_n==1'b0) begin
    cnt_c <= 6'd0;
  end
  else begin
    cnt_c <= cnt_n;
  end
end     



logic [7:0] cs_wave;                                                       
always @(posedge clk_40g or negedge rst_n) begin
  if(rst_n==1'b0) begin
    cs_wave <= 16'h0;
  end
  else begin
    case(cnt_c) 
          6'd0   : cs_wave <= {~data_out_r[0 ][7],data_out_r[0 ][6:0]};
          6'd1   : cs_wave <= {~data_out_r[1 ][7],data_out_r[1 ][6:0]};
          6'd2   : cs_wave <= {~data_out_r[2 ][7],data_out_r[2 ][6:0]};
          6'd3   : cs_wave <= {~data_out_r[3 ][7],data_out_r[3 ][6:0]};
          6'd4   : cs_wave <= {~data_out_r[4 ][7],data_out_r[4 ][6:0]};
          6'd5   : cs_wave <= {~data_out_r[5 ][7],data_out_r[5 ][6:0]};
          6'd6   : cs_wave <= {~data_out_r[6 ][7],data_out_r[6 ][6:0]};
          6'd7   : cs_wave <= {~data_out_r[7 ][7],data_out_r[7 ][6:0]};
          6'd8   : cs_wave <= {~data_out_r[8 ][7],data_out_r[8 ][6:0]};
          6'd9   : cs_wave <= {~data_out_r[9 ][7],data_out_r[9 ][6:0]};
          6'd10  : cs_wave <= {~data_out_r[10][7],data_out_r[10][6:0]};
          6'd11  : cs_wave <= {~data_out_r[11][7],data_out_r[11][6:0]};
          6'd12  : cs_wave <= {~data_out_r[12][7],data_out_r[12][6:0]};
          6'd13  : cs_wave <= {~data_out_r[13][7],data_out_r[13][6:0]};
          6'd14  : cs_wave <= {~data_out_r[14][7],data_out_r[14][6:0]};
          6'd15  : cs_wave <= {~data_out_r[15][7],data_out_r[15][6:0]};
          6'd16  : cs_wave <= {~data_out_r[16][7],data_out_r[16][6:0]};
          6'd17  : cs_wave <= {~data_out_r[17][7],data_out_r[17][6:0]};
          6'd18  : cs_wave <= {~data_out_r[18][7],data_out_r[18][6:0]};
          6'd19  : cs_wave <= {~data_out_r[19][7],data_out_r[19][6:0]};
          6'd20  : cs_wave <= {~data_out_r[20][7],data_out_r[20][6:0]};
          6'd21  : cs_wave <= {~data_out_r[21][7],data_out_r[21][6:0]};
          6'd22  : cs_wave <= {~data_out_r[22][7],data_out_r[22][6:0]};
          6'd23  : cs_wave <= {~data_out_r[23][7],data_out_r[23][6:0]};
          6'd24  : cs_wave <= {~data_out_r[24][7],data_out_r[24][6:0]};
          6'd25  : cs_wave <= {~data_out_r[25][7],data_out_r[25][6:0]};
          6'd26  : cs_wave <= {~data_out_r[26][7],data_out_r[26][6:0]};
          6'd27  : cs_wave <= {~data_out_r[27][7],data_out_r[27][6:0]};
          6'd28  : cs_wave <= {~data_out_r[28][7],data_out_r[28][6:0]};
          6'd29  : cs_wave <= {~data_out_r[29][7],data_out_r[29][6:0]};
          6'd30  : cs_wave <= {~data_out_r[30][7],data_out_r[30][6:0]};
          6'd31  : cs_wave <= {~data_out_r[31][7],data_out_r[31][6:0]};
          6'd32  : cs_wave <= {~data_out_r[32][7],data_out_r[32][6:0]};
          6'd33  : cs_wave <= {~data_out_r[33][7],data_out_r[33][6:0]};
          6'd34  : cs_wave <= {~data_out_r[34][7],data_out_r[34][6:0]};
          6'd35  : cs_wave <= {~data_out_r[35][7],data_out_r[35][6:0]};
          6'd36  : cs_wave <= {~data_out_r[36][7],data_out_r[36][6:0]};
          6'd37  : cs_wave <= {~data_out_r[37][7],data_out_r[37][6:0]};
          6'd38  : cs_wave <= {~data_out_r[38][7],data_out_r[38][6:0]};
          6'd39  : cs_wave <= {~data_out_r[39][7],data_out_r[39][6:0]};
          6'd40  : cs_wave <= {~data_out_r[40][7],data_out_r[40][6:0]};
          6'd41  : cs_wave <= {~data_out_r[41][7],data_out_r[41][6:0]};
          6'd42  : cs_wave <= {~data_out_r[42][7],data_out_r[42][6:0]};
          6'd43  : cs_wave <= {~data_out_r[43][7],data_out_r[43][6:0]};
          6'd44  : cs_wave <= {~data_out_r[44][7],data_out_r[44][6:0]};
          6'd45  : cs_wave <= {~data_out_r[45][7],data_out_r[45][6:0]};
          6'd46  : cs_wave <= {~data_out_r[46][7],data_out_r[46][6:0]};
          6'd47  : cs_wave <= {~data_out_r[47][7],data_out_r[47][6:0]};
          6'd48  : cs_wave <= {~data_out_r[48][7],data_out_r[48][6:0]};
          6'd49  : cs_wave <= {~data_out_r[49][7],data_out_r[49][6:0]};
          6'd50  : cs_wave <= {~data_out_r[50][7],data_out_r[50][6:0]};
          6'd51  : cs_wave <= {~data_out_r[51][7],data_out_r[51][6:0]};
          6'd52  : cs_wave <= {~data_out_r[52][7],data_out_r[52][6:0]};
          6'd53  : cs_wave <= {~data_out_r[53][7],data_out_r[53][6:0]};
          6'd54  : cs_wave <= {~data_out_r[54][7],data_out_r[54][6:0]};
          6'd55  : cs_wave <= {~data_out_r[55][7],data_out_r[55][6:0]};
          6'd56  : cs_wave <= {~data_out_r[56][7],data_out_r[56][6:0]};
          6'd57  : cs_wave <= {~data_out_r[57][7],data_out_r[57][6:0]};
          6'd58  : cs_wave <= {~data_out_r[58][7],data_out_r[58][6:0]};
          6'd59  : cs_wave <= {~data_out_r[59][7],data_out_r[59][6:0]};
          6'd60  : cs_wave <= {~data_out_r[60][7],data_out_r[60][6:0]};
          6'd61  : cs_wave <= {~data_out_r[61][7],data_out_r[61][6:0]};
          6'd62  : cs_wave <= {~data_out_r[62][7],data_out_r[62][6:0]};
          6'd63  : cs_wave <= {~data_out_r[63][7],data_out_r[63][6:0]}; 
        endcase
  end
end                              
endmodule
