//------------------------------------------------------------------------------
// CERN BE-CO-HT
// White Rabbit Trigger Distribution (WRTD)
// https://ohwr.org/projects/wrtd
//------------------------------------------------------------------------------
//
// unit name:   WrtdRepCap, WrtdRepCapCollection
//
// description: A SystemVerilog Class for a WRTD "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_REPCAP_INCLUDED
 `define __WRTD_REPCAP_INCLUDED

 `include "wrtd_definitions.svh"

virtual class WrtdRepCap;
   protected string name;
   protected WrtdId rep_cap_id;
   protected int    core;
   protected int    enabled;

   function new ( string name = "" );
      this.name  = name;
      this.rep_cap_id = new();
      clear();
   endfunction // new

   function void clear ( );
      this.rep_cap_id.clear();
      this.enabled = 0;
   endfunction // clear

   task mdisplay ( string str );
      string tmp;
      if (this.name == "")
        tmp = $sformatf("<%t> %s", $realtime, str);
      else
        tmp = $sformatf("[%s] <%t> %s", this.name, $realtime, str);
      $display (tmp);
   endtask // mdisplay

   function int get_core ( );
      return this.core;
   endfunction // get_core

   function void set_core ( int core );
      this.core = core;
   endfunction // set_core

   function string get_rep_cap_id ( );
      return this.rep_cap_id.get();
   endfunction // get_rep_cap_id

   function void set_rep_cap_id ( string id );
      this.rep_cap_id.set( id );
   endfunction // set_rep_cap_id

   function int match ( string id );
      return ( get_rep_cap_id().compare ( id ) == 0 );
   endfunction // is_equal

   function int is_free ( );
      return this.rep_cap_id.is_empty();
   endfunction // is_free

   function int is_enabled ( );
      return ( this.enabled > 0 );
   endfunction // is_enabled

   function void set_enable ( int enable );
      if ( enable > 0)
        this.enabled = 1;
      else
        this.enabled = 0;
   endfunction // set_enable

   function void set_disable ( );
      this.enabled = 0;
   endfunction // set_disable

   pure virtual function wrtd_data data_pack ( );

   pure virtual function void data_unpack ( wrtd_data data );

endclass //WrtdRepCap

class WrtdRepCapCollection;
   protected string name;
   WrtdRepCap collection[$];

   function new ( string name );
      this.name = name;
      this.collection.delete();
   endfunction // new

   task mdisplay ( string str );
      string tmp;
      if (this.name == "")
        tmp = $sformatf("<%t> %s", $realtime, str);
      else
        tmp = $sformatf("[%s] <%t> %s", this.name, $realtime, str);
      $display (tmp);
   endtask // mdisplay

   function void validate_id ( string rep_cap_id );
      if ( rep_cap_id.len() > `WRTD_ID_LEN )
        $error ( "repeated capability name '%s' is too long", rep_cap_id );
      if ( rep_cap_id.len() == 0 )
        $error ( "repeated capability name is null" );
   endfunction // validate_id

   function int add ( string rep_cap_id );
      int i, idx;

      validate_id ( rep_cap_id );

      idx = -1;

      for ( i = 0; i < this.collection.size(); i++ )
        begin

           if ( this.collection[i].match ( rep_cap_id ) )
             begin
                $error ( "'%s' repeated capability ID already exists", rep_cap_id );
                return -1;
             end
           if ( idx == -1 && this.collection[i].is_free() )
             idx = i;
        end

      if ( idx == -1 )
        $error ( "cannot add '%s' repeated capability, no space available", rep_cap_id );
      else
        this.collection[idx].set_rep_cap_id ( rep_cap_id );

      return idx;
   endfunction // add

   function int find ( string rep_cap_id );
      int i;

      validate_id ( rep_cap_id );

      for ( i = 0; i < this.collection.size(); i++ )
        if ( this.collection[i].match ( rep_cap_id ) )
          return i;

      return -1;
   endfunction // find

   function int remove ( string rep_cap_id );
      int idx;

      idx = find ( rep_cap_id );

      if ( idx == -1 )
        begin
           $error ( "%s repeated capability ID cannot be removed because it does not exist", rep_cap_id );
           return idx;
        end

      if ( this.collection[idx].is_enabled ( ) )
        $error ( "%s repeated capability ID cannot be removed because it is enabled", rep_cap_id );
      else
        this.collection[idx].clear();

      return idx;
   endfunction // remove

endclass // WrtdRepCapCollection

`endif //  `ifndef __WRTD_REPCAP_INCLUDED
