//------------------------------------------------------------------------------
// CERN BE-CO-HT
// White Rabbit Trigger Distribution (WRTD)
// https://ohwr.org/projects/wrtd
//------------------------------------------------------------------------------
//
// unit name:   WrtdRule
//
// description: A SystemVerilog Class for a WRTD "rule" repeated capability
//
//------------------------------------------------------------------------------
// Copyright CERN 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.
//------------------------------------------------------------------------------

`ifndef __WRTD_RULE_INCLUDED
 `define __WRTD_RULE_INCLUDED

 `include "wrtd_rep_cap.svh"

class WrtdRule extends WrtdRepCap;
   protected WrtdId        src;
   protected WrtdId        dst;
   protected byte unsigned dest_cpu;
   protected byte unsigned dest_ch;
   protected byte unsigned send_late;
   protected uint32_t      repeat_count;
   protected uint32_t      delay_ns;
   protected uint32_t      hold_off_ns;
   protected uint32_t      resync_period_ns;
   protected uint32_t      resync_factor;
   int                     hash_chain;
   protected uint32_t      rx_events;
   protected WrtdTstamp    rx_last;
   protected uint32_t      tx_events;
   protected WrtdTstamp    tx_last;
   protected uint32_t      lat_min_ns;
   protected uint32_t      lat_max_ns;
   protected uint32_t      lat_lo_ns;
   protected uint32_t      lat_hi_ns;
   protected uint32_t      lat_nbr;
   protected uint32_t      miss_holdoff;
   protected uint32_t      miss_late;
   protected uint32_t      miss_nosync;
   protected uint32_t      miss_overflow;
   protected WrtdTstamp    miss_last;
   protected WrtdTstamp    hold_off;
   protected uint32_t      seq;

   function new ( string name = "" );
      super.new ( name );
      this.src       = new();
      this.dst       = new();
      this.rx_last   = new();
      this.tx_last   = new();
      this.miss_last = new();
      this.hold_off  = new();
      clear();
   endfunction // new

   function void clear ( );
      super.clear();
      this.src.clear();
      this.dst.clear();
      this.rx_last.zero();
      this.tx_last.zero();
      this.miss_last.zero();
      this.hold_off.zero();
      this.dest_cpu         = 0;
      this.dest_ch          = 0;
      this.send_late        = 1;
      this.repeat_count     = 0;
      this.delay_ns         = 0;
      this.hold_off_ns      = 0;
      this.resync_period_ns = 0;
      this.resync_factor    = 0;
      this.hash_chain       = -1;
   endfunction // clear

   function wrtd_data data_pack ( );
      wrtd_data ret = new[`WRTD_RULE_WORD_SIZE];
      ret[0:3]   = this.rep_cap_id.data_pack();
      ret[4:7]   = this.src.data_pack();
      ret[8:11]  = this.dst.data_pack();
      ret[12]    = this.dest_cpu  << 0;
      ret[12]   |= this.dest_ch   << 8;
      ret[12]   |= this.enabled   << 16;
      ret[12]   |= this.send_late << 24;
      ret[13]    = this.repeat_count;
      ret[14]    = this.delay_ns;
      ret[15]    = this.hold_off_ns;
      ret[16]    = this.resync_period_ns;
      ret[17]    = this.resync_factor;
      ret[18]    = this.hash_chain;
      ret[19]    = this.rx_events;
      ret[20:22] = this.rx_last.data_pack();
      ret[23]    = this.tx_events;
      ret[24:26] = this.tx_last.data_pack();
      ret[27]    = this.lat_min_ns;
      ret[28]    = this.lat_max_ns;
      ret[29]    = this.lat_lo_ns;
      ret[30]    = this.lat_hi_ns;
      ret[31]    = this.lat_nbr;
      ret[32]    = this.miss_holdoff;
      ret[33]    = this.miss_late;
      ret[34]    = this.miss_nosync;
      ret[35]    = this.miss_overflow;
      ret[36:38] = this.miss_last.data_pack();
      ret[39:41] = this.hold_off.data_pack();
      ret[42]    = this.seq;
      return ret;
   endfunction // data_pack

   function void data_unpack ( wrtd_data data );
      this.rep_cap_id.data_unpack ( data[0:3] );
      this.src.data_unpack (data[4:7] );
      this.dst.data_unpack( data[8:11] );
      this.dest_cpu         = ( data[12] & 'h000000ff ) >> 0;
      this.dest_ch          = ( data[12] & 'h0000ff00 ) >> 8;
      this.enabled          = ( data[12] & 'h00ff0000 ) >> 16;
      this.send_late        = ( data[12] & 'hff000000 ) >> 24;
      this.repeat_count     = data[13];
      this.delay_ns         = data[14];
      this.hold_off_ns      = data[15];
      this.resync_period_ns = data[16];
      this.resync_factor    = data[17];
      this.hash_chain       = data[18];
      this.rx_events        = data[19];
      this.rx_last.data_unpack ( data[20:22] );
      this.tx_events        = data[23];
      this.tx_last.data_unpack ( data[24:26] );
      this.lat_min_ns       = data[27];
      this.lat_max_ns       = data[28];
      this.lat_lo_ns        = data[29];
      this.lat_hi_ns        = data[30];
      this.lat_nbr          = data[31];
      this.miss_holdoff     = data[32];
      this.miss_late        = data[33];
      this.miss_nosync      = data[34];
      this.miss_overflow    = data[35];
      this.miss_last.data_unpack ( data[36:38] );
      this.hold_off.data_unpack ( data[39:41] );
      this.seq              = data[42];
   endfunction // data_unpack

   function string get_src ( );
      return this.src.get();
   endfunction // get_src

   function string get_dst ( );
      return this.dst.get();
   endfunction // get_dst

   function void set_src ( string src );
      this.src.set ( src );
   endfunction // set_src

   function void set_dst ( string dst );
      this.dst.set ( dst );
   endfunction // set_src

   function void set_dest_cpu ( uint32_t dest_cpu );
     this.dest_cpu = dest_cpu;
   endfunction // set_dest_cpu

   function void set_dest_ch ( uint32_t dest_ch );
     this.dest_ch = dest_ch;
   endfunction // set_dest_ch

   function void set_delay_ns ( uint32_t delay_ns );
     this.delay_ns = delay_ns;
   endfunction // set_delay_ns

endclass //WrtdRule

`endif //  `ifndef __WRTD_RULE_INCLUDED
