-- SPDX-FileCopyrightText: 2016, MEN Mikro Elektronik GmbH
-- SPDX-License-Identifier: CERN-OHL-S-2.0+

--------------------------------------------------------------------------------
-- Title       : Error Module
-- Project     : 16z091-01
--------------------------------------------------------------------------------
-- File        : error.vhd
-- Author      : Susanne Reinfelder
-- Email       : susanne.reinfelder@men.de
-- Organization: MEN Mikro Elektronik Nuremberg GmbH
-- Created     : 03.12.2010
--------------------------------------------------------------------------------
-- Simulator   : ModelSim PE 6.6a / ModelSim AE 6.5e sp1
-- Synthesis   :
--------------------------------------------------------------------------------
-- Description :
-- errors on RxModule, TxModule or hard IP core are collected here and passed
-- to Wishbone modules through a FIFO
--------------------------------------------------------------------------------
-- Hierarchy   :
--    ip_16z091_01
--       rx_module
--          rx_ctrl
--          rx_get_data
--          rx_fifo
--          rx_len_cntr
--       wb_master
--       wb_slave
--       tx_module
--          tx_ctrl
--          tx_put_data
--          tx_compl_timeout
--          tx_fifo_data
--          tx_fifo_header
-- *     error
--          err_fifo
--       init
--       interrupt_core
--       interrupt_wb
--------------------------------------------------------------------------------
--
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;

entity error is
   port(
      clk               : in  std_logic;
      rst               : in  std_logic;
      wb_clk            : in  std_logic;
      wb_rst            : in  std_logic;
      
      -- Rx Module
      rx_tag_id         : in  std_logic_vector(7 downto 0);
      rx_ecrc_err       : in  std_logic;
      rx_type_fmt_err   : in  std_logic_vector(1 downto 0);
      
      -- Tx Module
      tx_compl_abort    : in  std_logic;
      tx_timeout        : in  std_logic;
      
      -- Interrupt
      wb_num_err        : in  std_logic;
      
      -- Wishbone
      error_ecrc_err    : out std_logic;
      error_timeout     : out std_logic;
      error_tag_id      : out std_logic_vector(7 downto 0);
      error_cor_ext_rcv : out std_logic_vector(1 downto 0);
      error_cor_ext_rpl : out std_logic;
      error_rpl         : out std_logic;
      error_r2c0        : out std_logic;
      error_msi_num     : out std_logic;
      
      -- IP Core
      derr_cor_ext_rcv  : in  std_logic_vector(1 downto 0);
      derr_cor_ext_rpl  : in  std_logic;
      derr_rpl          : in  std_logic;
      r2c_err0          : in  std_logic;
      cpl_err           : out std_logic_vector(6 downto 0);
      cpl_pending       : out std_logic
   );
end entity error;

-- ****************************************************************************

architecture error_arch of error is

-- internal signals -----------------------------------------------------------
signal err_fifo_clr       : std_logic;
signal err_fifo_wr_enable : std_logic;
signal err_fifo_in        : std_logic_vector(15 downto 0);
-- uncomment next line when increasing FIFO depth
-- signal err_fifo_full      : std_logic;
signal err_fifo_rd_enable : std_logic;
signal err_fifo_out       : std_logic_vector(15 downto 0);
signal err_fifo_empty     : std_logic;
signal get_value          : std_logic;
signal wb_num_err_q       : std_logic;
signal wb_num_err_qq      : std_logic;
-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
signal ip_error_in   : std_logic_vector(14 downto 0);
signal ip_error_last : std_logic_vector(14 downto 0) := (others => '0');
-------------------------------------------------------------------------------

begin
-- instantiate components -----------------------------------------------------
  err_fifo_comp: entity work.generic_async_fifo
    generic map (
      g_data_width => 16,
      g_size => 8,
      g_show_ahead => False,
      g_with_rd_empty => True,
      g_with_rd_full => False,
      g_with_rd_almost_empty => False,
      g_with_rd_almost_full => False,
      g_with_rd_count => False,
      g_with_wr_empty => False,
      g_with_wr_full => False,
      g_with_wr_almost_empty => False,
      g_with_wr_almost_full => False,
      g_with_wr_count => False,
      g_almost_empty_threshold => 1,
      g_almost_full_threshold => 1,
      g_memory_implementation_hint => open
      )
    port map (
      rst_n_i => err_fifo_clr,

      clk_wr_i => clk,
      d_i => err_fifo_in,
      we_i => err_fifo_wr_enable,
      wr_empty_o => open,
      wr_full_o => open,
      wr_almost_empty_o => open,
      wr_almost_full_o => open,
      wr_count_o => open,

      clk_rd_i => wb_clk,
      q_o => err_fifo_out,
      rd_i => err_fifo_rd_enable,
      rd_empty_o => err_fifo_empty,
      rd_full_o => open,
      rd_almost_empty_o => open,
      rd_almost_full_o => open,
      rd_count_o => open
      );

-------------------------------------------------------------------------------
   
   fifo_wr : process(clk, rst)
   
   begin
      if(rst = '1') then
         err_fifo_wr_enable <= '0';
         err_fifo_in        <= (others => '0');
         err_fifo_clr       <= '1';
         ip_error_last      <= (others => '0');

      elsif(clk'event and clk = '1') then
         err_fifo_clr <= '0';
         
         -- store errors if new error occred
         if(ip_error_last /= ip_error_in) then
            err_fifo_wr_enable <= '1';
            err_fifo_in        <= '0' & ip_error_in;
            ip_error_last      <= ip_error_in;
         end if;
         
         -- reset signals
         if(err_fifo_wr_enable = '1') then
            err_fifo_wr_enable <= '0';
            err_fifo_in        <= (others => '0');
         end if;
      end if;
   end process fifo_wr;

-------------------------------------------------------------------------------
   fifo_rd : process(wb_clk, wb_rst)
   
   begin
      if(wb_rst = '1') then
         error_timeout     <= '0';
         error_r2c0        <= '0';
         error_rpl         <= '0';
         error_cor_ext_rpl <= '0';
         error_cor_ext_rcv <= (others => '0');
         error_ecrc_err    <= '0';
         error_tag_id      <= (others => '0');
         error_msi_num     <= '0';
         
         err_fifo_rd_enable <= '0';
         get_value          <= '0';
         wb_num_err_q       <= '0';
         wb_num_err_qq      <= '0';
      elsif(wb_clk'event and wb_clk = '1') then
         -- sample wb_num_err because this is synchronous to clk
         wb_num_err_q  <= wb_num_err;
         wb_num_err_qq <= wb_num_err_q;
         
         -- read values as soon as they appear
         if(err_fifo_empty = '0') then
            err_fifo_rd_enable <= '1';
         end if;
         
         -- reset enable an start analysis of value read from FIFO
         if(err_fifo_rd_enable = '1') then
            err_fifo_rd_enable <= '0';
            get_value          <= '1';
         end if;
         
         -- propagate error signals to outer environment
         if(get_value = '1') then
            get_value         <= '0';
            error_timeout     <= err_fifo_out(14);
            error_r2c0        <= err_fifo_out(13);
            error_rpl         <= err_fifo_out(12);
            error_cor_ext_rpl <= err_fifo_out(11);
            error_cor_ext_rcv <= err_fifo_out(10 downto 9);
            error_ecrc_err    <= err_fifo_out(8);
            error_tag_id      <= err_fifo_out(7 downto 0);
         else
            error_timeout     <= '0';
            error_r2c0        <= '0';
            error_rpl         <= '0';
            error_cor_ext_rpl <= '0';
            error_cor_ext_rcv <= (others => '0');
            error_ecrc_err    <= '0';
            error_tag_id      <= (others => '0');
         end if;
         
         -- propagate error signals to outer environment
         error_msi_num <= wb_num_err_qq;
      end if;
   end process fifo_rd;
-------------------------------------------------------------------------------
   -- capture occuring errors
   ip_error_in(14)          <= '1' when tx_timeout = '1' else '0';
   ip_error_in(13)          <= '1' when r2c_err0 = '1' else '0';
   ip_error_in(12)          <= '1' when derr_rpl = '1' else '0';
   ip_error_in(11)          <= '1' when derr_cor_ext_rpl = '1' else '0';
   ip_error_in(10 downto 9) <= derr_cor_ext_rcv when derr_cor_ext_rcv /= "00" else "00";
   ip_error_in(8)           <= '1' when rx_ecrc_err = '1' else '0';
   ip_error_in(7 downto 0)  <= rx_tag_id when rx_ecrc_err = '1' else (others => '0');
   
   cpl_err(6) <=  '0';
   cpl_err(5) <=  '0' when rst = '1' else
                  '1' when rx_type_fmt_err = "01" else
                  '0';
   cpl_err(4) <=  '0' when rst = '1' else
                  '1' when rx_type_fmt_err = "10" else
                  '0';
   cpl_err(3) <=  '0';
   cpl_err(2) <=  '0' when rst = '1' else
                  '1' when tx_compl_abort = '1' else
                  '0';
   cpl_err(1 downto 0) <= (others => '0');
   cpl_pending <= '0';
-------------------------------------------------------------------------------
end architecture error_arch;
