-- ------------------------------------------------------------------------
-- 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 model
-- ------------------------------------------------------------------------
-- Revision history  :
--
--   $Log$
-- ------------------------------------------------------------------------

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

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

use     work.bfm_hamm_rom_pkg.all;




--Functionality:
-- This is model of synchronous memory, that can be written
-- Memory is defined as shared variable, so it is possible to write and read same address of memory at one time moment.
-- Memory first write input data on desired address of memory and then read this written data from the same address
-- If desired mode is to first read last data and then write new data, it can be changed in p_rom_ctrl_process

-- ------------------------------------------------------------------------ --
--                                                                   Entity --
-- ------------------------------------------------------------------------ --
entity rom is
  generic (
    -- checkers control
    g_MSG_ON                  : boolean := true;
	-- enable/disable checking of unknown input values
	g_X_CHECKS_ON             : boolean := true;
    -- unique identification
    g_MID                     : string
  );
  port (
    -- inputs -----------
    -- Main OSC clock to drive communication with ROM
    CLK         : in   std_logic;
    -- data from coder, that schould be written to memry on currently operated address
    WRITE_DATA  : in   std_logic_vector(c_ENCODED_DATA_WIDTH-1 downto 0);
    --currently operated address
    ADDR        : in   std_logic_vector(c_ROM_ADDR_WIDTH-1 downto 0);
    -- Write enable signal
    WE          : in   std_logic;
    --outputs -----------
    --data read from the memory from currently operated address, that are send to decoder
    READ_DATA   : out  std_logic_vector(c_ENCODED_DATA_WIDTH-1 downto 0);
	-- Bus funtional model error
    BFM_ERR     : out std_logic
  );
end rom;

-- ------------------------------------------------------------------------ --
--                                                             Architecture --
-- ------------------------------------------------------------------------ --
architecture beh of rom is



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

  -- ROM memory
  shared variable rom1 : t_rom_type := (others => (others=> '0'));

  -- flag, that unknown value was detected on input signal from coder
  signal x_check_err : std_logic := '0';
  -- flag, that simulation has too short clock period
  signal clk_period_err : std_logic := '0';

begin

  -- Signal for testcase, that rom bus funcional model error was detected
  BFM_ERR <= x_check_err or clk_period_err;

  -- process for checking unknown values on input signal from coder
  p_x_check: process
  begin
    if g_X_CHECKS_ON = true then
      if now < c_START_SIMULATION_DELAY then
        wait for c_START_SIMULATION_DELAY;
      end if;
      wait on WRITE_DATA; 
      if is_x(WRITE_DATA) then
        msg(g_MID, "X value on WRITE_DATA");
		x_check_err <= '1';
      end if;
	end if;
  end process p_x_check;

-- process to communicate with rom_pkg procedures:
p_rom_set: process

begin
  
  wait on rom_set_req;
    if (rom1_var.rom_set_op = c_WRITE_ROM) then --if rom setting opeation is set to '1' => write
	  
	  --check if clock perid is long enough for securing clock setup and hold times
	  if (g_MSG_ON) then
	    if (rom_timing.we_hold + rom_timing.we_setup > c_CLK_PERIOD) then
          msg(g_MID, "-- Too short clock period --");
          clk_period_err <= '1';
        end if;
	  end if;    
	
	  
	  if (CLK = '1') and (CLK'last_event < rom_timing.we_hold) then
        wait for rom_timing.we_hold - CLK'last_event;
      elsif (CLK = '0') and (CLK'last_event > (c_CLK_PERIOD/2) - rom_timing.we_setup) then
        wait on CLK;
        wait for rom_timing.we_hold;
      end if;
	  rom1(rom1_var.addr) := rom1_var.data;

    elsif (rom1_var.rom_set_op) = c_READ_ROM then --if rom setting opeation is set to '0' => read
       rom1_var.data := rom1(rom1_var.addr);
 
    end if;
    rom_set_req_help <= not rom_set_req_help; --handshake signal for rom_pkg

end process p_rom_set;


  -- synchronous processes
  -- -------------------------------------------------------------------------

--ROM memory control process
p_rom_ctrl: process (CLK)
begin

  if rising_edge(CLK) then  
    -- Memory is set to first write new data and then read this written data 
    if (WE = '1') then 
      --synchronous write to memory
      rom1(to_integer(unsigned(ADDR))) := WRITE_DATA;
    end if;

    --synchronous read written data
    READ_DATA <= rom1(to_integer(unsigned(ADDR)));

  end if;
end process p_rom_ctrl;

end beh;

