`include "vme64x_bfm.svh"
`include "svec_vme_buffers.svh"

`include "fdelay_board.svh"
`include "simdrv_fine_delay.svh"
`include "ideal_timestamper.svh"


module delay_meas(input enable, input a, input b);

   mailbox tag_a, tag_b;

   event   q_notempty;
   
   initial begin
      tag_a = new(1024);
      tag_b = new(1024);
   end

   always@(posedge a) begin
      if(enable) tag_a.put($time);
   end
   
   always@(posedge b) begin
      if(enable) tag_b.put($time);
   end
   
   
   

   initial forever begin
      wait(tag_a.num() > 0 && tag_b.num() > 0);
      
      while(tag_a.num() > 0 && tag_b.num() > 0)
        begin
           longint ta, tb, delta;
           
           tag_a.get(ta);
           tag_b.get(tb);

           delta = tb - ta;

           $display("Delay: %.3f ns",  real'(delta) / real'(1ns) );
        end
   end
endmodule // delay_meas



module main;

   reg rst_n = 0;
   reg clk_125m = 0, clk_20m = 0;

   always #4ns clk_125m <= ~clk_125m;
   always #25ns clk_20m <= ~clk_20m;
   
   initial begin
      repeat(20) @(posedge clk_125m);
      rst_n = 1;
   end

   IFineDelayFMC I_fmc0(), I_fmc1();
   
   IVME64X VME(rst_n);

   `DECLARE_VME_BUFFERS(VME.slave);

   svec_top #(
              .g_with_wr_phy(0),
              .g_simulation(1)
              ) DUT (
		 .clk_125m_pllref_p_i(clk_125m),
		 .clk_125m_pllref_n_i(~clk_125m),
		 .clk_125m_gtp_p_i(clk_125m),
		 .clk_125m_gtp_n_i(~clk_125m),
		 .clk_20m_vcxo_i(clk_20m),
                
		 .rst_n_i(rst_n),
                 
		 `WIRE_VME_PINS(8),
                 `WIRE_FINE_DELAY_PINS(0, I_fmc0),
                 `WIRE_FINE_DELAY_PINS(1, I_fmc1)
	         );

   wire trig0, trig1;
   wire [3:0] out0, out1;
   reg        pulse_enable = 0;
   
   
   random_pulse_gen
     #(
       .g_pulse_width  (100ns),
       .g_min_spacing  (1001ns),
       .g_max_spacing  (1001.1ns),
       .g_repetition(1),
       .g_burst_spacing(3ns))
   U_Gen0
     (
      .enable_i(pulse_enable),
      .pulse_o(trig0)
      );
   
   fdelay_board U_Board0 
     (
      .trig_i(trig0),
      .out_o(out0),
      .fmc(I_fmc0.board)
      );

  delay_meas U_DMeas0 (pulse_enable, trig0, out0[0]);

   ideal_timestamper tsu_in(
                            .clk_ref_i(I_fmc0.clk_ref_p),
                            .rst_n_i(rst_n),
                            .enable_i(1'b1),
                            .trig_a_i(trig0),
                            .csync_p1_i(1'b0));
   
   
   task automatic init_vme64x_core(ref CBusAccessor_VME64x acc);
      /* map func0 to 0x80000000, A32 */
      acc.write('h7ff63, 'h80, A32|CR_CSR|D08Byte3);
      acc.write('h7ff67, 0, CR_CSR|A32|D08Byte3);
      acc.write('h7ff6b, 0, CR_CSR|A32|D08Byte3);
      acc.write('h7ff6f, 36, CR_CSR|A32|D08Byte3);
      acc.write('h7ff33, 1, CR_CSR|A32|D08Byte3);
      acc.write('h7fffb, 'h10, CR_CSR|A32|D08Byte3); /* enable module (BIT_SET = 0x10) */

   endtask // init_vme64x_core
   
   initial begin
      CBusAccessor_VME64x acc = new(VME.master);
      CBusAccessor acc_casted = CBusAccessor'(acc);
      Timestamp dly;
      
      CSimDrv_FineDelay drv0;
      uint64_t d;
      
      #20us;

      init_vme64x_core(acc);
      acc_casted.set_default_xfer_size(A32|SINGLE|D32);
      
      drv0 = new(acc, 'h10000);
      drv0.init();

      dly=new;
      dly.from_ps(800000);
      drv0.config_output(0, CSimDrv_FineDelay::DELAY, 1, dly, 250000);
      
      $display("Init done");

      pulse_enable = 1;

   

      forever begin
         //       drv0.rbuf_update();
         //         if(drv0.poll())
         Timestamp ts, ts_ref;
         //              ts = drv0.get();

         while(ts_q_fd0.size() == 0)
           #1ns;
         
         ts = ts_q_fd0.pop_front();
         $display("TS: %.3f", ts.flatten());
         
         while(tsu_in.poll())
           begin
              ts_ref = tsu_in.get();
           end

         $display("TS: %.3f, ref: %.3f, delta: %.3f", ts.flatten(), ts_ref.flatten(), ts_ref.flatten() - ts.flatten());
         
         
      end
   end // initial begin

      Timestamp ts_q_fd0[$];
   


      always@(posedge DUT.dcm0_clk_ref_0)
        begin
           if(DUT.U_FineDelay_Core0.tag_valid)
             begin
                Timestamp tr;
                tr = new;
                
                $display("Got a tag");
                tr.coarse = DUT.U_FineDelay_Core0.tag_coarse;
                tr.utc = 0;
                tr.frac = DUT.U_FineDelay_Core0.tag_frac;

                ts_q_fd0.push_back(tr);
                
                
                
             end
           
        end

   
  
endmodule // main



