//------------------------------------------------------------------------------
// CERN BE-CO-HT
// White Rabbit Trigger Distribution (WRTD)
// https://ohwr.org/projects/wrtd
//------------------------------------------------------------------------------
//
// unit name:   main
//
// description: Testbench for the SVEC-based FMC TDC+FD WRTD reference design.
//
//------------------------------------------------------------------------------
// Copyright CERN 2018-2019
//------------------------------------------------------------------------------
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 2.0 (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-2.0.
// Unless required by applicable law or agreed to in writing, software,
// hardware and materials distributed under this License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
// or implied. See the License for the specific language governing permissions
// and limitations under the License.
//------------------------------------------------------------------------------

`timescale 1ns/1ps

`include "vme64x_bfm.svh"
`include "wrtd_driver.svh"

`define VME_OFFSET      'h8000_0000
`define TDC_DIRECT_BASE `VME_OFFSET + 'h0001_8000
`define MT_BASE         `VME_OFFSET + 'h0002_0000


module main;

   wire clk_sys, rst_sys_n;

   wire sfp_txp, sfp_txn, sfp_rxp, sfp_rxn;

   IVME64X VME(rst_sys_n);

   dut_env DUT (VME, clk_sys, rst_sys_n, sfp_txp, sfp_txn, sfp_rxp, sfp_rxn);

   IMockTurtleIRQ MtIrqMonitor (`MT_ATTACH_IRQ(DUT.DUT.cmp_mock_turtle));

   assign sfp_rxp = sfp_txp;
   assign sfp_rxn = sfp_txn;

   WrtdDrv dev;

   initial begin

      CBusAccessor_VME64x acc;

      acc = new(VME.tb);

      $timeformat (-6, 3, "us", 10);

      #5us;

      /* 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) */

      acc.set_default_modifiers(A32 | D32 | SINGLE);
      /* Hack around CBusAccessor to make it work like CBusAccessor_VME64x. This is needed
       because WrtdDev expects a CBusAccesor and will not respect the m_default_modifiers value
       of CBusAccessor_VME64x when performing reads/writes. */
      acc.set_default_xfer_size(A32 | D32 | SINGLE);

      acc.write(`TDC_DIRECT_BASE + 'h4, 'h40);
      #5us;

      dev = new (acc, `MT_BASE, MtIrqMonitor, "DUT");

      dev.init();

      dev.add_rule ( "rule0" );
      dev.set_rule ( "rule0", "NET0", "LC-O1", 200000 );
      dev.enable_rule ( "rule0" );

      dev.add_rule ( "rule1" );
      dev.set_rule ( "rule1", "NET1", "LC-O2", 200000 );
      dev.enable_rule ( "rule1" );

      dev.add_rule ( "rule2" );
      dev.set_rule ( "rule2", "NET2", "LC-O3", 200000 );
      dev.enable_rule ( "rule2" );

      dev.add_rule ( "rule3" );
      dev.set_rule ( "rule3", "LC-I1", "NET0", 0 );
      dev.enable_rule ( "rule3" );

      dev.add_rule ( "rule4" );
      dev.set_rule ( "rule4", "LC-I2", "NET1", 0 );
      dev.enable_rule ( "rule4" );

      dev.add_rule ( "rule5" );
      dev.set_rule ( "rule5", "LC-I3", "NET2", 0 );
      dev.enable_rule ( "rule5" );

      // Set dead-time
      acc.write(`TDC_DIRECT_BASE + 'h4, 'h40);

      #5us;

      // Enable channels
      acc.write(`TDC_DIRECT_BASE + 'h0, 'h1f);

      // Force start_fpga from TDC to make sure that the FSM has been started
      force DUT.DUT.U_TDC_Core.cmp_tdc_mezz.cmp_tdc_core.start_from_fpga = 'b1;
      #100ns;
      release DUT.DUT.U_TDC_Core.cmp_tdc_mezz.cmp_tdc_core.start_from_fpga;

      dev.mdisplay("Configuration complete, ready to accept pulses...");

   end

   initial begin
      forever begin
         if ( ( dev != null ) && ( dev.ready ) )
         dev.update ();
         #1us;
      end
   end

endmodule // main
