-- ------------------------------------------------------------------------
-- ON Semiconductor Proprietary and Confidential Information.
-- ------------------------------------------------------------------------

-- ------------------------------------------------------------------------
-- Company           : ON Semiconductor
-- ------------------------------------------------------------------------
-- File              : $RCSfile: ncutilities.vhd,v $
-- ------------------------------------------------------------------------
-- Last Modified     : $Date: 2016/04/01 08:03:44 $
-- Last Modified By  : $Author: fg7g4t $
-- Revision          : $Revision: 1.1 $
-- ------------------------------------------------------------------------
-- Description       :
--
--      This package mimic the behavior of NCSIM NCMIROR by using of
--      Modelsim SIGNAL SPY procedure calls
--
--      Note: The namig of file violates the standard naming convetions,
--      each package  should have a "_pkg" identifier behind the name of
--      the package, this is done to  100% follow  the  Cadance NCMIRROR
--      implementation.
--
-- ------------------------------------------------------------------------
-- Revision history  :
--
--   $Log: ncutilities.vhd,v $
--   Revision 1.1  2016/04/01 08:03:44  fg7g4t
--   Initial revision (directory structure & standard scripts revision 255).
--

library ieee;
use ieee.std_logic_1164.all;

library modelsim_lib;
use modelsim_lib.util.all;

-- ***********************************************
-- Mimic of NCSIM NCMIRROR functionality by the
-- Modelsim SIGNAL SPY
-- ***********************************************

package ncutilities is

-- ***********************************************
-- TYPE DEFINITIONS
-- ***********************************************

-- pointer on unconstrained array of characters (resp. pointer on string)
type str_pointer is access string;


-- ***********************************************
-- PROCEDURE HEADERS
-- ***********************************************

-- mirror the global signal (verilog or vhdl) on
-- the specified local signal
procedure nc_mirror
     (
      constant destination : in string;
      constant source      : in string;
      constant verbose     : in string := "");

-- deposit the value of global signal
procedure nc_deposit
     (
      constant source      : in string;
      constant value       : in string;
      constant in_time     : in string := "";
      constant delay_type  : in string := "transport";
      constant verbose     : in string := "");

-- force the value of global signal
procedure nc_force
     (
      constant source      : in string;
      constant value       : in string;
      constant verbose     : in string := "");

-- release the forced global signal
procedure nc_release
     (
      constant source      : in string;
      constant keepvalue   : in string := "";
      constant verbose     : in string := "");

end ncutilities;

package body ncutilities is

-- ***********************************************
-- IMPLEMENTATION OF PROCEDURES
-- ***********************************************

-- internal package procedure, replace  NCSIM delimiter
-- characted ":" with  Modelsim hierarchy delimiter "/"
procedure replace_delimiter
     (
      constant in_data    : in    string;
      variable out_data   : inout string) is
begin

  -- copy of input data
  out_data(1 to in_data'length) := in_data(1 to in_data'length);

  -- replace ":" with "/" (in NCSIM hierarchy delimiter
  -- is ":", instead of it Modelsim is using "/")
  -- Destination
  for i in in_data'length downto 1 loop
      if (out_data(i)=':') then
          out_data(i):='/';
      end if;
  end loop;

end procedure replace_delimiter;

-- internal package procedure, performing following replace
-- operation :
-- "'1'" - "1"
-- "'0'" - "0",
-- in case if input string  is  longer  than 3-character is
-- passed on output whitout any modification
procedure convert_one_bit_string
     (
      variable in_data : in  string;
      variable out_data: out str_pointer) is

begin

  -- performe the string modification
  if (in_data'length = 3 and in_data(3) = ''' and in_data(1) = ''') then
     out_data := new string(1 to 1);
     out_data.all(1) := in_data(2);
  -- pass unmodified data on output
  else
     out_data     := new string(1 to in_data'length);
     out_data.all := in_data;
  end if;

end procedure;

-- internal package procedure, performing following replace operation
-- convert verilog to VHDL std_logic_vector string
-- example "8'b00010001" - "00010001"
procedure convert_more_bit_string
     (
      variable in_data : in  string;
      variable out_data: out str_pointer) is

variable conversion_done : boolean := false;

begin

  -- performe the string modification for binary constants
  for i in in_data'range loop
    if in_data(i) = 'b' or in_data(i) = 'B' then
      out_data     := new string(1 to in_data'length-i);
      out_data.all := in_data(i+1 to in_data'length);
      conversion_done := true;
      exit;
    end if;
  end loop;
  -- pass unmodified data on output
  if (conversion_done = false) then
     out_data     := new string(1 to in_data'length);
     out_data.all := in_data;
  end if;

end procedure;


-- internal package function
-- converts string verbose request to integer code
function verbose_to_int(verbose : in  string) return integer is
begin
  if (verbose = "") then return 0;
                    else return 1;
  end if;
end function verbose_to_int;



-- spy_mirror, mirror the global signal (verilog or vhdl) on
-- the specified local signal
procedure nc_mirror
     (
      constant destination : in string;
      constant source      : in string;
      constant verbose     : in string := "") is

variable tmp_destination : str_pointer;
variable tmp_source      : str_pointer;
variable verbose_int     : integer;

begin

   -- dynamic allocation of temporary variables
   tmp_destination     := new string(1 to destination'length);
   tmp_source          := new string(1 to source'length);
   tmp_destination.all := destination;
   tmp_source.all      := source;

   -- replace ":" with "/" (in NCSIM hierarchy delimiter
   -- is ":", instead of it Modelsim is using "/")
   -- Destination
   replace_delimiter(destination, tmp_destination.all);
   replace_delimiter(source     , tmp_source.all);

   -- call Modelsim Signal SPY procedures
   verbose_int := verbose_to_int(verbose);

   init_signal_spy( tmp_source.all,
                    tmp_destination.all,
                    verbose_int,
                    1
                  );

   -- deallocate the dynamic allocated variables
   deallocate(tmp_destination);
   deallocate(tmp_source);

end procedure nc_mirror;

-- force the value of global signal
procedure nc_deposit
     (
      constant source      : in string;
      constant value       : in string;
      constant in_time     : in string := "";
      constant delay_type  : in string := "transport";
      constant verbose     : in string := "") is

variable tmp_source   : str_pointer;
variable tmp_value_0  : str_pointer;
variable tmp_value_1  : str_pointer;
variable tmp_value_2  : str_pointer;
variable tmp_in_time  : time;

begin

   -- convert in_time from string to decimal value,
   -- and convert absolute delay into the relative
   -- one
   if (in_time /= "") then
      tmp_in_time := time'value(in_time);
      -- transform absolute delay into the relative
      if (tmp_in_time > now) then
         tmp_in_time := tmp_in_time - now;
      else
        assert(false)
           report "NCUTILITIES : NC_DEPOSIT /time/ parameter less than actual" &
                  " simulation time"
          severity error;
      end if;
   else
      tmp_in_time := 0 ns;
   end if;

   -- compatibility check, Modelsim does  not support
   -- the "inertial" delay in case of deposit command
   if (delay_type /= "transport") then
      assert(false)
        report "NCUTILITIES : Modelsim does not support /delay_type/ other than /transport/."
         severity error;
   end if;

   -- dynamic allocation of temporary variables
   tmp_source      := new string(1 to source'length);
   tmp_source.all  := source;
   tmp_value_0     := new string(1 to value'length);
   tmp_value_0.all := value;

   -- replace ":" with "/" (in NCSIM hierarchy delimiter
   -- is ":", instead of it Modelsim is using "/")
   -- Destination
   replace_delimiter(source, tmp_source.all);

   -- correct the /value/ if required
   convert_one_bit_string(tmp_value_0.all, tmp_value_1);
   convert_more_bit_string(tmp_value_1.all, tmp_value_2);

   -- call Modelsim Signal SPY procedures
   if (verbose = "") then
      signal_force( tmp_source.all,
                    tmp_value_2.all,
                      tmp_in_time,
                      deposit,
                      -1 ms,
                      0 );
   else
      signal_force( tmp_source.all,
                    tmp_value_2.all,
                      tmp_in_time,
                      deposit,
                      -1 ms,
                      1 );
   end if;

   -- deallocate the dynamic allocated variables
   deallocate(tmp_source);
   deallocate(tmp_value_0);
   deallocate(tmp_value_1);
   deallocate(tmp_value_2);

end procedure nc_deposit;

-- force the value of global signal
procedure nc_force
     (
      constant source      : in string;
      constant value       : in string;
      constant verbose     : in string := "") is

variable tmp_source  : str_pointer;
variable tmp_value_0 : str_pointer;
variable tmp_value_1 : str_pointer;
variable tmp_value_2 : str_pointer;

begin

   -- dynamic allocation of temporary variables
   tmp_source      := new string(1 to source'length);
   tmp_source.all  := source;
   tmp_value_0     := new string(1 to value'length);
   tmp_value_0.all := value;

   -- replace ":" with "/" (in NCSIM hierarchy delimiter
   -- is ":", instead of it Modelsim is using "/")
   -- Destination
   replace_delimiter(source, tmp_source.all);

   -- correct the /value/ if required
   convert_one_bit_string(tmp_value_0.all, tmp_value_1);
   convert_more_bit_string(tmp_value_1.all, tmp_value_2);

   -- call Modelsim Signal SPY procedures
   if (verbose = "") then
      signal_force( tmp_source.all,
                    tmp_value_2.all,
                      0 ns,
                      freeze,
                      -1 ms,
                      0 );
   else
      signal_force( tmp_source.all,
                    tmp_value_2.all,
                      0 ns,
                      freeze,
                      -1 ms,
                      1 );
   end if;

   -- deallocate the dynamic allocated variables
   deallocate(tmp_source);
   deallocate(tmp_value_0);
   deallocate(tmp_value_1);
   deallocate(tmp_value_2);

end procedure nc_force;

-- release the forced global signal
procedure nc_release
     (
      constant source      : in string;
      constant keepvalue   : in string := "";
      constant verbose     : in string := "") is

variable tmp_source :  str_pointer;

begin

   -- compatibility check, Modelsim has no equivalent
   -- to  "keepvalue" parameter of  NCSIM  nc_release
   -- procedure
   if (keepvalue /= "") then
      assert(false)
        report "NCUTILITIES : Modelsim does not support /keepvalue/ parameter of /nc_release/."
         severity error;
   end if;

   -- dynamic allocation of temporary variables
   tmp_source      := new string(1 to source'length);
   tmp_source.all  := source;

   -- replace ":" with "/" (in NCSIM hierarchy delimiter
   -- is ":", instead of it Modelsim is using "/")
   -- Destination
   replace_delimiter(source, tmp_source.all);

   -- call Modelsim Signal SPY procedures
   if (verbose = "") then
      signal_release( tmp_source.all,
                      0 );
   else
      signal_release( tmp_source.all,
                      1 );
   end if;

   -- deallocate the dynamic allocated variables
   deallocate(tmp_source);

end procedure nc_release;

end ncutilities;

