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

-- ------------------------------------------------------------------------
-- Company           : ON Semiconductor
-- ------------------------------------------------------------------------
-- File              : $RCSfile$
-- ------------------------------------------------------------------------
-- Last Modified     : $Date: 2016/06/01$
-- Last Modified By  : $Author: Jan Bares $
-- Revision          : $Revision$
-- ------------------------------------------------------------------------
-- Description       : ROM master model package. All verification 
--                     environment is driven from testcase by procedures,
--                     declared in this package.                  
-- ------------------------------------------------------------------------
-- Revision history  :
--
--   $Log$
-- ------------------------------------------------------------------------

-- ------------------------------------------------------------------------ --
--                                                                Libraries --
-- ------------------------------------------------------------------------ --
library ieee;
use     ieee.std_logic_1164.all;
--use     ieee.numeric_std.all; -- redundant

library work;
use     work.messages_pkg.all;
use     work.coder_pkg.all;
use     work.rom_pkg.all;

use     work.bfm_hamm_rom_pkg.all;

-- ------------------------------------------------------------------------ --
--                                                      package declaration --
-- ------------------------------------------------------------------------ --
package rom_master_pkg is


  -- ---------------------------------------------------------------------------
  --  General constants
  -- ---------------------------------------------------------------------------

  constant c_READ_ONLY : std_logic := '0';
  constant c_WRITE : std_logic := '1';

    -- checkers control
  constant c_MSG_ON           : boolean := true;
  -- rom_master_pkg messages ID
  constant c_MID              : string    := "rom_master_pkg";

  -- ---------------------------------------------------------------------------
  --  Data types
  -- ---------------------------------------------------------------------------

  --read/write operation information  
  type t_rw_data_type is record
    addr : integer;
    data : std_logic_vector (c_INF_DATA_WIDTH - 1 downto 0);
	encoded_data : std_logic_vector (c_ENCODED_DATA_WIDTH - 1 downto 0);
    rw_op : std_logic; -- read/write operation => read = '0', write = '1'
  end record;

  -- error memory type
  type t_err_mem_type is array (0 to (2**c_ROM_ADDR_WIDTH - 1)) of integer;

  --control memory type
  type t_ctrl_mem_type is array (0 to (2**c_ROM_ADDR_WIDTH - 1)) of std_logic_vector(c_ENCODED_DATA_WIDTH-1 downto 0);

  -- ---------------------------------------------------------------------------
  --  Shared Variables
  -- ---------------------------------------------------------------------------

  --read/write operation information
  shared variable rw_data_var : t_rw_data_type := (
    addr => 0,
    data => (others => '0'),
	encoded_data => (others => '0'),
    rw_op => c_READ_ONLY --read
    );

  -- error memory
  shared variable err_mem : t_err_mem_type := (
    others => 0
    );

  -- control memory
  shared variable ctrl_mem : t_ctrl_mem_type := (
    others => (others=> '0'));

  -- ---------------------------------------------------------------------------
  --  Signals
  -- ---------------------------------------------------------------------------
  -- reqest signals -> handshake with rom_master.beh -------------------------------
  signal rw_req : std_logic := '0';
  signal rw_req_help : std_logic := '0';

  

  -----------------------------------------------------------------------------
  --procedure declaration
  -----------------------------------------------------------------------------

  
  -- procedure to write data to one address of rom memory
  -- -------------------------------------------------------------------------
  procedure proc_write_rom (
    addr                : in  integer;
    data                : in  std_logic_vector(c_ENCODED_DATA_WIDTH - 1 downto 0);
    signal req          : inout std_logic
  );

  -- procedure to write data to one address of rom memory
  -- -------------------------------------------------------------------------
  procedure proc_write_data (
    addr                : in  integer;
    data                : in  std_logic_vector(c_INF_DATA_WIDTH - 1 downto 0);
    fast                : in  boolean := false;
    signal req          : inout std_logic
  );

  -- procedure to read data from one address of rom memory
  -- -------------------------------------------------------------------------
  procedure proc_read_rom (
    addr                : in  integer;
    fast                : in  boolean := false;
    signal read_bfm_err : out std_logic;
    signal req          : inout std_logic
  );

  -- procedure to write error value to one address of rom memory
  -- -------------------------------------------------------------------------
  procedure proc_insert_err_val (
    err_addr     : in  integer;
    err_word     : in  std_logic_vector(c_ENCODED_DATA_WIDTH - 1 downto 0);
    signal req   : inout std_logic
  );


  -- group procedures -----------

  -- procedure to write data to all address of rom memory
  -- -------------------------------------------------------------------------
  procedure proc_write_all_rom (
    data                : in  std_logic_vector(c_INF_DATA_WIDTH -1 downto 0);
    fast                : in  boolean := true;
    signal req          : inout std_logic
  );

  -- procedure to read data from all address of rom memory
  -- -------------------------------------------------------------------------
  procedure proc_read_all_rom (
    fast                : in  boolean := true;
    signal read_bfm_err : out std_logic;
    signal req          : inout std_logic
  );

  -- procedure to clear all rom memory
  -- -------------------------------------------------------------------------
  procedure proc_clear_rom (
    signal req : inout std_logic
  );

  -- procedure to write error value to all address of rom memory
  -- -------------------------------------------------------------------------
  procedure proc_insert_all_err_val (
    err_word     : in  std_logic_vector(c_ENCODED_DATA_WIDTH - 1 downto 0);
    signal req   : inout std_logic
  );


end rom_master_pkg;

-- ------------------------------------------------------------------------ --
--                                                             package body --
-- ------------------------------------------------------------------------ --
package body rom_master_pkg is

-- procedure to instantly write data to one address of rom memory
-- input data are encoded
-- -------------------------------------------------------------------------
  procedure proc_write_rom (
    addr         : in  integer;
    data         : in  std_logic_vector(c_ENCODED_DATA_WIDTH - 1 downto 0);
    signal req   : inout std_logic
  ) is
  begin

    proc_write(addr => addr, data => data, req => req);
    
  end procedure;

-- procedure to write data to one address of rom memory
-- input data are unencoded
-- -------------------------------------------------------------------------
  procedure proc_write_data (
    addr         : in  integer;
    data         : in  std_logic_vector(c_INF_DATA_WIDTH - 1 downto 0);
    fast         : in  boolean := false;
    signal req   : inout std_logic
  ) is
    variable encoded_data : std_logic_vector(c_ENCODED_DATA_WIDTH -1 downto 0) := (others => '0');
  begin
    
    encoded_data := encode_data(data_in => data);
 
    if fast = true then
  
      proc_write_rom(addr => addr, data => encoded_data, req => req);
      
      --save original data to control memory on currently operated address
      ctrl_mem(addr) := encoded_data;
      --reset error memory currently operated address
      err_mem(addr) := 0;
      

    else
      rw_data_var.addr := addr;
      rw_data_var.data := data;
	  rw_data_var.encoded_data := encoded_data;
      rw_data_var.rw_op := c_WRITE;
      req <= not req;
      
      wait until rw_req_help'event;
    end if;
  end procedure;



-- procedure to read data from one address of rom memory
-- -------------------------------------------------------------------------
  procedure proc_read_rom (
    addr                : in  integer;
    fast                : in  boolean := false;
    signal read_bfm_err : out std_logic;
    signal req          : inout std_logic
  ) is
    variable read_data : std_logic_vector(c_ENCODED_DATA_WIDTH - 1 downto 0) := (others => '0');
    variable error_word : std_logic_vector(c_ENCODED_DATA_WIDTH - 1 downto 0) := (others => '0');
    variable num_ones : integer := 0;
  begin
--    read_bfm_err <= '0';
  
    if fast = true then
      proc_read(addr => addr, read_data => read_data, req => req);
      error_word := read_data xor ctrl_mem(addr);

      --count multiplicity of error -> number of bits in error word that are equal to '1'
      for i in 0 to (c_ENCODED_DATA_WIDTH-1) loop
        if error_word(i) = '1' then
          num_ones := num_ones + 1;
        end if;
      end loop;

      if num_ones > 3 then
        num_ones := 3;
      end if;

      if num_ones /= err_mem(addr) then
        read_bfm_err <= '1';
        if (c_MSG_ON) then
          msg(c_MID, "-- Wrong data on output  while reading address " & integer'image(addr) & " --");

        end if;
      end if;


    else
      rw_data_var.addr := addr;
      rw_data_var.rw_op := c_READ_ONLY;
      req <= not req;
      wait until rw_req_help'event;
    end if;

  end procedure;


  -- procedure to write error value to one address of rom memory
  -- -------------------------------------------------------------------------
  procedure proc_insert_err_val (
     err_addr     : in  integer;
     err_word     : in  std_logic_vector(c_ENCODED_DATA_WIDTH - 1 downto 0);
     signal req   : inout std_logic
  ) is

     variable read_data      : std_logic_vector(c_ENCODED_DATA_WIDTH-1 downto 0);
     -- number of bits in error word that are equal to one
     variable num_ones : integer := 0; -- number of bits in error word that are equal to one
     -- number of errors that occured on one address of memory, if >= 3, then is equal to "11" (undetectable error)  
     variable num_err  : integer := 0; 
     variable error_data     : std_logic_vector(c_ENCODED_DATA_WIDTH-1 downto 0);


  begin
     proc_read(addr => err_addr, read_data => read_data, req => req);
	 
     error_data := read_data xor err_word;
     proc_write(addr => err_addr, data => error_data, req => req);

     --count multiplicity of error -> number of bits in error word that are equal to '1'
     for i in 0 to (c_ENCODED_DATA_WIDTH - 1) loop
       if err_word(i) = '1' then
         num_ones := num_ones + 1;
       end if;
     end loop;

     -- count number of errors, that occured on currently operated address
     num_err := (err_mem(err_addr)) + num_ones;
     -- save number of errors, that occured on currently operated address to error_memory variable
     if (num_err > 3) then
       num_err := 3;
     end if; 
     
     err_mem(err_addr) := num_err;
         
  end procedure;



---group procedures-------------

  -- procedure to write data to all address of rom memory
  -- -------------------------------------------------------------------------
  procedure proc_write_all_rom (
    data                : in  std_logic_vector(c_INF_DATA_WIDTH -1 downto 0);
    fast                : in  boolean := true;
    signal req          : inout std_logic
  ) is
  begin

    for i in 0 to ((2**c_ROM_ADDR_WIDTH) -1) loop
      proc_write_data(addr => i, data => data, fast => fast, req => req);
    end loop;

  end procedure;



  -- procedure to read data from all address of rom memory
  -- -------------------------------------------------------------------------
  procedure proc_read_all_rom (
    fast                : in boolean := true;
    signal read_bfm_err : out std_logic;
    signal req          : inout std_logic
  ) is

  begin

--    read_bfm_err <= '0';

    for i in 0 to ((2**c_ROM_ADDR_WIDTH) -1) loop
      proc_read_rom(addr => i, fast => fast, read_bfm_err => read_bfm_err, req => req);
 --     msg(c_MID, "-- read_bfm_err2 on address " & integer'image(i) & " is " & std_logic'image(read_bfm_err2) & " --");
 --     msg(c_MID, "-- rom_set_req on address " & integer'image(i) & " is " & std_logic'image(req) & " --");
    end loop;

  end procedure;
  
  -- procedure to clear rom memory
  -- -------------------------------------------------------------------------
  procedure proc_clear_rom (
    signal req : inout std_logic
  ) is
  begin

    proc_write_all_rom (data => (others => '0'), fast => true, req => req);

  end procedure;


  -- procedure to write error value to all address of rom memory
  -- -------------------------------------------------------------------------
  procedure proc_insert_all_err_val (
     err_word     : in  std_logic_vector(c_ENCODED_DATA_WIDTH - 1 downto 0);
     signal req   : inout std_logic
  ) is
  begin

    for i in 0 to ((2**c_ROM_ADDR_WIDTH) -1)
    loop
      proc_insert_err_val(err_addr => i, err_word => err_word, req => req);
    end loop;

  end procedure;


end rom_master_pkg;