OpenCores
URL https://opencores.org/ocsvn/funbase_ip_library/funbase_ip_library/trunk

Subversion Repositories funbase_ip_library

[/] [funbase_ip_library/] [trunk/] [TUT/] [ip.hwp.communication/] [fh_ring/] [1.0/] [vhd/] [ring_router.vhd] - Rev 145

Compare with Previous | Blame | View Log

-------------------------------------------------------------------------------
-- File        : ring_router.vhdl
-- Description : Routes packets in Ring network.
--               Four io channels,
--                 i.e. two to neighbor routers, one for opposite neighbor
--                 and one for processing element.
--
--               Neighbor connections have identifiers: fwd, rev, and diag
--               referring to direction in ring
--               
--               All output channels have one fifo buffer.
--               Routers are identified with three-part address
--                two-part ring id (direction and distance from center ring)
--                router id within the ring
--
--               Size of packet (including address) is the same as fifo_depth_g
--
--               
-- Author      : Jussi Nieminen after Erno Salminen's Octagon router
-- Date        : 10.04.2006
-- Modified    : 12.02.2009     JN      Forked from the Octagon router.
 
-------------------------------------------------------------------------------
 
-------------------------------------------------------------------------------
-- Copyright (c) 2011 Tampere University of Technology
-------------------------------------------------------------------------------
--  This file is part of Transaction Generator.
--
--  Transaction Generator is free software: you can redistribute it and/or
--  modify it under the terms of the Lesser GNU General Public License as
--  published by the Free Software Foundation, either version 3 of the License,
--  or (at your option) any later version.
--
--  Transaction Generator is distributed in the hope that it will be useful,
--  but WITHOUT ANY WARRANTY; without even the implied warranty of
--  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
--  Lesser GNU General Public License for more details.
--
--  You should have received a copy of the Lesser GNU General Public License
--  along with Transaction Generator.  If not, see
--  <http://www.gnu.org/licenses/>.
-------------------------------------------------------------------------------
 
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
 
 
entity ring_router is
 
  generic (
    nbr_of_routers_g   : integer := 8;
    data_width_g       : integer := 0;
    dateline_en_g      : integer := 0;
    stfwd_en_g         : integer := 1;
    pkt_len_g          : integer;
    len_flit_en_g      : integer := 0;
    oaddr_flit_en_g    : integer := 0;
    fifo_depth_g       : integer;
    router_id_g        : integer := 0;
    diag_en_g          : integer := 1;
    net_freq_g         : integer;
    ip_freq_g          : integer;
    sim_dbg_ena_g      : integer := 0
    );
  port (
    clk_net : in std_logic;
    clk_ip  : in std_logic;
    rst_n   : in std_logic;
 
    data_fwd_in  : in  std_logic_vector (data_width_g-1 downto 0);
    re_fwd_out   : out std_logic;
    empty_fwd_in : in  std_logic;
    full_fwd_in  : in  std_logic;
 
    data_rev_in  : in  std_logic_vector (data_width_g-1 downto 0);
    re_rev_out   : out std_logic;
    empty_rev_in : in  std_logic;
    full_rev_in  : in  std_logic;
 
    -- diag ports enabled with generic
    data_diag_in  : in  std_logic_vector (data_width_g-1 downto 0);
    re_diag_out   : out std_logic;
    empty_diag_in : in  std_logic;
    full_diag_in  : in  std_logic;
 
    data_ip_tx_in   : in  std_logic_vector (data_width_g-1 downto 0);
    we_ip_tx_in     : in  std_logic;
    empty_ip_tx_out : out std_logic;
    full_ip_tx_out  : out std_logic;
 
    data_fwd_out  : out std_logic_vector (data_width_g-1 downto 0);
    re_fwd_in     : in  std_logic;
    empty_fwd_out : out std_logic;
    full_fwd_out  : out std_logic;
 
    data_rev_out  : out std_logic_vector (data_width_g-1 downto 0);
    re_rev_in     : in  std_logic;
    empty_rev_out : out std_logic;
    full_rev_out  : out std_logic;
 
    -- diag ports enabled with generic
    data_diag_out  : out std_logic_vector (data_width_g-1 downto 0);
    re_diag_in     : in  std_logic;
    empty_diag_out : out std_logic;
    full_diag_out  : out std_logic;
 
    data_ip_rx_out  : out std_logic_vector (data_width_g-1 downto 0);
    re_ip_rx_in     : in  std_logic;
    full_ip_rx_out  : out std_logic;
    empty_ip_rx_out : out std_logic
    );
 
end ring_router;
 
 
 
architecture rtl of ring_router is
 
 
  -- Set dbg_level=0 for synthesis
  constant dbg_level_c : integer range 0 to 3 := 0;
 
  type dbg_value_arr is array (0 to 1) of std_logic;
  constant dbg_value_c : dbg_value_arr := ('0', 'Z');
 
 
  -- this should be made generic later..?
  constant addr_width_c : integer := 15;
 
  -- There are always at least 3 bidir ports: IP, clockwise, counterclkwise
  -- Possibly also; diagonal port
  constant n_ports_c  : integer range 0 to 5 := 3 + diag_en_g;
  signal n_ports_dbgr : integer              := n_ports_c;
 
  -- Constants for accessing arrays (e.g. state_regs)
  constant ip_c     : integer := 0;
  constant fwd_c    : integer := 1;
  constant rev_c    : integer := 2;
  constant diag_c   : integer := 3;
  constant no_dir_c : integer := n_ports_c;           -- Illegal index
 
  component multiclk_fifo
    generic (
      re_freq_g    : integer;
      we_freq_g    : integer;
      depth_g      : integer;
      data_width_g : integer);
    port (
      clk_re    : in  std_logic;
      clk_we    : in  std_logic;
      rst_n     : in  std_logic;
      data_in   : in  std_logic_vector (data_width_g-1 downto 0);
      we_in     : in  std_logic;
      full_out  : out std_logic;
      one_p_out : out std_logic;
      re_in     : in  std_logic;
      data_out  : out std_logic_vector (data_width_g-1 downto 0);
      empty_out : out std_logic;
      one_d_out : out std_logic);
  end component;
 
  component fifo
    generic (
      data_width_g : integer := 0;
      depth_g      : integer := 0);
    port (
      clk       : in  std_logic;
      rst_n     : in  std_logic;
      data_in   : in  std_logic_vector (data_width_g-1 downto 0);
      we_in     : in  std_logic;
      one_p_out : out std_logic;
      full_out  : out std_logic;
      data_out  : out std_logic_vector (data_width_g-1 downto 0);
      re_in     : in  std_logic;
      empty_out : out std_logic;
      one_d_out : out std_logic
      );
  end component;  --fifo;
 
 
  -- Function that decides shortest to reach target within the ring
  function router_func (
    constant dst_addr   : integer;      --std_logic_vector ( 3-1 downto 0);
    constant own_addr   : integer)
    return integer is
    variable rel_addr_v : integer range -nbr_of_routers_g+1 to nbr_of_routers_g;
  begin  -- router_func
 
    -- address relative to this router, target's distance from
    -- this router when going forward
    -- (e.g. nbr_of_routers - 1 means target is the next router backwards)
    rel_addr_v := (dst_addr - own_addr);
    if rel_addr_v < 0 then
      rel_addr_v := rel_addr_v + nbr_of_routers_g;
    end if;
 
    if (rel_addr_v = 0) then
      -- right dst
      return ip_c;
 
    elsif (rel_addr_v <= nbr_of_routers_g / 4) then
      return fwd_c;
 
    elsif (rel_addr_v >= nbr_of_routers_g - nbr_of_routers_g / 4) then
      return rev_c;
 
    else
      if diag_en_g = 1 then
        return diag_c;
      elsif rel_addr_v > nbr_of_routers_g / 2 then
        return rev_c;
      else
        return fwd_c;
      end if;
    end if;
 
  end router_func;
 
 
 
  -- Internal types and signals. Thse are mapped to router's inputs
  -- Arrays are easier to handle than names with direction identification
  -- (e.g. data_arr(i) vs. data_fwd)
  type data_arr_type is array (n_ports_c-1 downto 0) of std_logic_vector (data_width_g-1 downto 0);
  type ctrl_arr_type is array (n_ports_c-1 downto 0) of std_logic;
  type source_type is array (n_ports_c-1 downto 0) of integer range 0 to 5;
  type counter_arr_type is array (n_ports_c-1 downto 0) of integer range 0 to pkt_len_g;  --fifo_depth_g;
  type channel_arr_type is array (n_ports_c-1 downto 0) of integer range 0 to 1;
 
 
  signal Incoming_data  : data_arr_type;
  signal Incoming_empty : ctrl_arr_type;
  signal Incoming_full  : ctrl_arr_type;
  signal send_counter_r : counter_arr_type;
  signal pkt_len_arr_r  : counter_arr_type;
 
  -- From fifos. Mapped directly to outputs pins 
  signal data_from_fifo  : data_arr_type;
  signal full_from_fifo  : ctrl_arr_type;
  signal empty_from_fifo : ctrl_arr_type;  -- this goes also to ctrl
 
  -- signals to and from fwd and rev fifos
  signal data_from_fwd0 : std_logic_vector( data_width_g - 1 downto 0 );
  signal data_from_fwd1 : std_logic_vector( data_width_g - 1 downto 0 );
  signal data_from_rev0 : std_logic_vector( data_width_g - 1 downto 0 );
  signal data_from_rev1 : std_logic_vector( data_width_g - 1 downto 0 );
  signal full_from_fwd0 : std_logic;
  signal full_from_fwd1 : std_logic;
  signal full_from_rev0 : std_logic;
  signal full_from_rev1 : std_logic;
  signal empty_from_fwd0 : std_logic;
  signal empty_from_fwd1 : std_logic;
  signal empty_from_rev0 : std_logic;
  signal empty_from_rev1 : std_logic;
  signal empty_from_fwd : std_logic;
  signal empty_from_rev : std_logic;
  signal we_fwd0 : std_logic;
  signal we_fwd1 : std_logic;
  signal we_rev0 : std_logic;
  signal we_rev1 : std_logic;
  signal re_fwd0 : std_logic;
  signal re_fwd1 : std_logic;
  signal re_rev0 : std_logic;
  signal re_rev1 : std_logic;
 
  -- controlling outputs from fwd and rev
  signal fwd_pkt_counter_r : integer;
  signal rev_pkt_counter_r : integer;
  signal fwd_chan_sel_r : std_logic;
  signal rev_chan_sel_r : std_logic;
 
  signal fwd_pkt_len_r : integer;
  signal rev_pkt_len_r : integer;
 
  -- From ctrl
  signal data_ctrl_fifo_r : data_arr_type;
  signal we_ctrl_fifo_r   : ctrl_arr_type;
  signal re_r             : ctrl_arr_type;
 
  -- 2006/10/23 Try wormhole, combinatorial enable signals
  signal re_tmp : ctrl_arr_type;
  signal we_tmp : ctrl_arr_type;
 
  signal data_reg_valid_r   : ctrl_arr_type;  -- 2006/10/26
  signal data_ctrl_fifo_dbg : data_arr_type;
 
 
  -- State registers
  signal State_writing_r : std_logic_vector (n_ports_c-1 downto 0);  -- 0=ip,1=
  signal State_reading_r : std_logic_vector (n_ports_c-1 downto 0);  -- 0=ip,1=
 
  -- state_src_r(i) tells which port the source for output port i
  signal state_src_r : source_type;     -- 0=ip,1=
 
  -- state_dst_r(i) tells which port the destination for input port i
  signal state_dst_r : source_type;
 
  -- state_channel_r(i) tells which channel to use for output i
  signal state_channel_r : channel_arr_type;
 
 
  -- Marks which input is checked on current cycle
  --signal curr_src_r : integer range 0 to n_ports_c-1;
 
  -- Decoded address in input port pointed by curr_src_r, _not_ a register!
  --signal curr_dst : integer range 0 to n_ports_c;
  -- new type 2006/10/23, ES
  type dst_arr_type is array (n_ports_c-1 downto 0) of integer range 0 to n_ports_c;
  signal curr_dst          : dst_arr_type;
  signal curr_dst_resolved : dst_arr_type;
  signal n_req_dbgr        : dst_arr_type;
  signal curr_channel      : channel_arr_type;
 
 
 
  type addr_arr_type is array (n_ports_c-1 downto 0) of integer;
 
  signal router_addr : addr_arr_type;
 
 
  signal start_idx_r : integer range 0 to n_ports_c-1;  -- 28.11 for round-robin resolution
 
  -- this should be generic...
  constant len_width_c : integer := 8;
 
-----------------------------------------------------------------------------
begin  -- rtl
-----------------------------------------------------------------------------
 
 
  -- Concurrent assignments
  -- Connect fifo status signals to outputs
  empty_fwd_out   <= empty_from_fwd;
  empty_rev_out   <= empty_from_rev;
  empty_ip_rx_out <= empty_from_fifo (ip_c);  -- from ip_rx_fifo 
 
  full_fwd_out   <= full_from_fifo (fwd_c);
  full_rev_out   <= full_from_fifo (rev_c);
  full_ip_rx_out <= full_from_fifo (ip_c);  -- from ip_rx_fifo 
 
  -- Separate arrays signals into outputs
  re_fwd_out <= re_tmp (fwd_c);         -- 2006/10/23 re_r (fwd_c);
  re_rev_out <= re_tmp (rev_c);         -- 2006/10/23 re_r (rev_c);
 
 
  -- Collect inputs into array
  Incoming_data (fwd_c) <= data_fwd_in;
  Incoming_data (rev_c) <= data_rev_in;
  -- incoming_data/empty/full (ip_c) comes directly from rx-fifo
 
  Incoming_empty (fwd_c) <= empty_fwd_in;
  Incoming_empty (rev_c) <= empty_rev_in;
  empty_ip_tx_out        <= Incoming_empty (ip_c);  -- from ip_tx_fifo
 
  Incoming_full (fwd_c) <= full_fwd_in;
  Incoming_full (rev_c) <= full_rev_in;
  full_ip_tx_out        <= Incoming_full (ip_c);  -- from ip_tx_fifo
 
 
 
  connect_diag_signals : if diag_en_g = 1 generate
    data_diag_out           <= data_from_fifo (diag_c);  -- when (dbg_level_c = 0 or empty_from_fifo (fwd_c) = '0') else (others => 'Z');
    empty_diag_out          <= empty_from_fifo (diag_c);
    full_diag_out           <= full_from_fifo (diag_c);
    re_diag_out             <= re_tmp (diag_c);  -- 2006/10/23 re_r (diag_c);
    Incoming_data (diag_c)  <= data_diag_in;
    Incoming_empty (diag_c) <= empty_diag_in;
    Incoming_full (diag_c)  <= full_diag_in;
  end generate connect_diag_signals;
 
  not_map_diag_fifo : if diag_en_g = 0 generate
    data_diag_out  <= (others => dbg_value_c(sim_dbg_ena_g));  --(others => 'Z');
    empty_diag_out <= '1';
    full_diag_out  <= '1';
    re_diag_out    <= '0';
  end generate not_map_diag_fifo;
 
 
 
  -- Debug
  -- Easier to trace if outputs are 'Z' when output fifo is empty
  -- (Comment out the "when part" for synthesis
  -- e.g."data_fwd_out <= data_from_fifo (fwd_c);  -- when data_from_fifo and so on")
  -- Done with if-generate, 08.06.2006 es
 
--   dbg_tristate_off: if dbg_level_c = 0 generate
--     data_fwd_out   <= data_from_fifo (fwd_c);
--     data_rev_out   <= data_from_fifo (rev_c); 
--     data_ip_rx_out <= data_from_fifo (ip_c); 
--   end generate dbg_tristate_off;
 
--  dbg_tristate_on : if dbg_level_c > 0 generate
  data_fwd_out   <= data_from_fifo (fwd_c);  -- when (dbg_level_c = 0 or empty_from_fifo (fwd_c) = '0') else (others => 'Z');
  data_rev_out   <= data_from_fifo (rev_c);  -- when (dbg_level_c = 0 or empty_from_fifo (fwd_c) = '0') else (others => 'Z');
  data_ip_rx_out <= data_from_fifo (ip_c);  --  when (dbg_level_c = 0 or empty_from_fifo (fwd_c) = '0') else (others => '0');
--  end generate dbg_tristate_on;
 
 
 
  -----------------------------------------------------------------------------
  -- Component mappings
  -----------------------------------------------------------------------------
 
  -- Fifo data outputs are connected to router's outputs (via intermediate signal, though)
 
  -- 4 FIFOS are always included to outports
  -- Data going to ip, multiclk
  Ip_fifo_rx : multiclk_fifo
    generic map (
      re_freq_g    => ip_freq_g,
      we_freq_g    => net_freq_g,
      data_width_g => data_width_g,
      depth_g      => fifo_depth_g
      )
    port map (
      clk_re    => clk_ip,
      clk_we    => clk_net,
      rst_n     => rst_n,
      data_in   => data_ctrl_fifo_r (ip_c),
      we_in     => we_tmp (ip_c),
      full_out  => full_from_fifo (ip_c),
      data_out  => data_from_fifo (ip_c),
      re_in     => re_ip_rx_in,            -- router input
      empty_out => empty_from_fifo (ip_c)  --,
      );
 
  -- Data coming from ip, multiclk
  Ip_fifo_tx : multiclk_fifo
    generic map (
      re_freq_g    => net_freq_g,
      we_freq_g    => ip_freq_g,
      data_width_g => data_width_g,
      depth_g      => fifo_depth_g
      )
    port map (
      clk_re   => clk_net,
      clk_we   => clk_ip,
      rst_n    => rst_n,
      -- Fifo inputs come straight router inputs (=from ip)
      data_in  => data_ip_tx_in,
      full_out => Incoming_full (ip_c),
      we_in    => we_ip_Tx_in,
 
      -- Fifo outputs go ctrl logic
      data_out  => Incoming_data (ip_c),
      empty_out => Incoming_empty (ip_c),
      re_in     => re_tmp (ip_c)        --re_r (ip_c)
      );
 
 
  -- two forward fifos to enable two channels
  fwd_fifo_0 : fifo
    generic map (
      data_width_g => data_width_g,
      depth_g      => fifo_depth_g
      )
    port map (
      clk       => clk_net,
      rst_n     => rst_n,
      data_in   => data_ctrl_fifo_r (fwd_c),
      we_in     => we_fwd0,
      full_out  => full_from_fwd0,
      data_out  => data_from_fwd0,
      re_in     => re_fwd0,           -- router input
      empty_out => empty_from_fwd0
      );
 
  fwd_fifo_1 : fifo
    generic map (
      data_width_g => data_width_g,
      depth_g      => fifo_depth_g
      )
    port map (
      clk       => clk_net,
      rst_n     => rst_n,
      data_in   => data_ctrl_fifo_r (fwd_c),
      we_in     => we_fwd1,
      full_out  => full_from_fwd1,
      data_out  => data_from_fwd1,
      re_in     => re_fwd1,           -- router input
      empty_out => empty_from_fwd1
      );
 
  -- two rev fifos
  rev_fifo_0 : fifo
    generic map (
      data_width_g => data_width_g,
      depth_g      => fifo_depth_g
      )
    port map (
      clk       => clk_net,
      rst_n     => rst_n,
      data_in   => data_ctrl_fifo_r (rev_c),
      we_in     => we_rev0,
      full_out  => full_from_rev0,
      data_out  => data_from_rev0,
      re_in     => re_rev0,
      empty_out => empty_from_rev0
      );
 
  rev_fifo_1 : fifo
    generic map (
      data_width_g => data_width_g,
      depth_g      => fifo_depth_g
      )
    port map (
      clk       => clk_net,
      rst_n     => rst_n,
      data_in   => data_ctrl_fifo_r (rev_c),
      we_in     => we_rev1,
      full_out  => full_from_rev1,
      data_out  => data_from_rev1,
      re_in     => re_rev1,
      empty_out => empty_from_rev1
      );
 
  -- 2 Optional fifos
  map_diag_fifo : if diag_en_g = 1 generate
    diag_fifo : fifo
      generic map (
        data_width_g => data_width_g,
        depth_g      => fifo_depth_g
        )
      port map (
        clk       => clk_net,
        rst_n     => rst_n,
        data_in   => data_ctrl_fifo_r (diag_c),
        we_in     => we_tmp (diag_c),
        full_out  => full_from_fifo (diag_c),
        data_out  => data_from_fifo (diag_c),
        re_in     => re_diag_in,        -- router input
        empty_out => empty_from_fifo (diag_c)
        );
  end generate map_diag_fifo;
 
 
  -----------------------------------------------------------------------------
  read_en_tmp : process (we_ctrl_fifo_r, re_r,
                        data_reg_valid_r,
                        state_src_r, state_dst_r,
                        full_from_fifo,
                        Incoming_empty --,
                        --send_counter_r
                         )
 
  begin  -- process read_en_tmp
    for i in 0 to n_ports_c-1 loop
 
      -- i viittaa kohteeseen (fifo)
      if state_src_r (i) = no_dir_c then
        we_tmp (i) <= '0';
 
      else
        we_tmp (i) <= we_ctrl_fifo_r (i)
                      and data_reg_valid_r (i)
                      and (not (full_from_fifo (i)));
      end if;
 
      -- i viittaa lähteeseen (=input_port)
      if state_dst_r (i) = no_dir_c then
        -- sisääntulossa i ei ole järkevää dataa
        re_tmp (i) <= '0';
      else
        -- ei lueta sisääntulosta i ellei
        --  a) tilakone ole lukemass sieltä (re_r pitää olla 1)
        --  b) sisääntulossa on validia dataa  (empty pitää olla 0)
        --  c) kohde ei ole varattu
        re_tmp (i) <= re_r (i)
                      and (not Incoming_empty (i))
                      and (not full_from_fifo (state_dst_r (i)));
      end if;
 
    end loop;  -- i
  end process read_en_tmp;
 
 
  -----------------------------------------------------------------------------
  -- select right fifo according to channel
  select_channels: process (we_tmp, state_channel_r,
                            data_from_fwd0, data_from_fwd1,
                            data_from_rev0, data_from_rev1,
                            empty_from_fwd0, empty_from_fwd1,
                            empty_from_rev0, empty_from_rev1,
                            full_from_fwd0, full_from_fwd1,
                            full_from_rev0, full_from_rev1,
                            re_fwd_in, re_rev_in,
                            fwd_chan_sel_r, rev_chan_sel_r)
  begin  -- process select_channels
 
 
    -- decide which fifo will get the data:
    -- if there's channel 1 data coming, we have to direct out
    -- signals from the fifo 1
    if state_channel_r(fwd_c) = 1 then
      we_fwd1 <= we_tmp(fwd_c);
      we_fwd0 <= '0';
      empty_from_fifo(fwd_c) <= empty_from_fwd1;
      full_from_fifo(fwd_c)  <= full_from_fwd1;
    else
      we_fwd0 <= we_tmp(fwd_c);
      we_fwd1 <= '0';
      empty_from_fifo(fwd_c) <= empty_from_fwd0;
      full_from_fifo(fwd_c)  <= full_from_fwd0;
    end if;
 
    if state_channel_r(rev_c) = 1 then
      we_rev1 <= we_tmp(rev_c);
      we_rev0 <= '0';
      full_from_fifo(rev_c)  <= full_from_rev1;
      empty_from_fifo(rev_c) <= empty_from_rev1;
    else
      we_rev0 <= we_tmp(rev_c);
      we_rev1 <= '0';
      full_from_fifo(rev_c)  <= full_from_rev0;
      empty_from_fifo(rev_c) <= empty_from_rev0;
    end if;
 
 
 
    -- decide from which fifo the data goes out
    if fwd_chan_sel_r = '1' then
      data_from_fifo(fwd_c)  <= data_from_fwd1;
      re_fwd1                <= re_fwd_in;
      re_fwd0                <= '0';
      empty_from_fwd         <= empty_from_fwd1;
    else
      data_from_fifo(fwd_c)  <= data_from_fwd0;
      re_fwd0                <= re_fwd_in;
      re_fwd1                <= '0';
      empty_from_fwd         <= empty_from_fwd0;
    end if;
 
    -- same for the rev fifo
    if rev_chan_sel_r = '1' then
      data_from_fifo(rev_c)  <= data_from_rev1;
      re_rev1                <= re_rev_in;
      re_rev0                <= '0';
      empty_from_rev         <= empty_from_rev1;
    else
      data_from_fifo(rev_c)  <= data_from_rev0;
      re_rev0                <= re_rev_in;
      re_rev1                <= '0';
      empty_from_rev         <= empty_from_rev0;
    end if;
 
 
  end process select_channels;
 
 
 
 
  ------------------------------------------------------------------------------
  -- Parallel routing (all ports prt cycle)
  ------------------------------------------------------------------------------
  -- !!! without postponed Incoming_data is not updated
  --     before this process and overflow occurs on
  --     router_addr !!! 11.9.2006 HP
  -- PROC
  -- Check where the incoming packet is heading
  -- Input ports are handled one per clock cycle
  Check_dst : postponed
    process (State_reading_r,
             router_addr,
             Incoming_data,
             Incoming_empty,
             Incoming_full)
 
      variable resolved_dest_v : integer range 0 to n_ports_c - 1;
      variable incoming_channel_v : std_logic;
 
    begin  -- process Check_dst
 
      -- 1) if (No read operation yet on the curr source port)
      --      and (Complete packet coming from curr src port)  -- store_and-forward
      --      and (there is data (=addr) on curr src port)  -- cut-through
      --      
      --      2) if (packet is going to right direction from center ring)
      --         3) if (target column)          => data goes to ip
      --         3) elsif (toward west)
      --         3) else (toward east)
      --
      --      2) else wrong direction
      --          away from center
      --          towards center
      -- 1) else                         => no packet arriving on curr src port
 
      for src_i in 0 to n_ports_c-1 loop
 
        router_addr (src_i) <= no_dir_c;  --0;
 
        if State_reading_r (src_i) = '0'
          and ((Incoming_full (src_i) = '1' and stfwd_en_g = 1)
               or
               (Incoming_empty (src_i) = '0'and stfwd_en_g = 0))
        then                            -- 1)
 
          router_addr(src_i) <= conv_integer (unsigned (Incoming_data (src_i) (addr_width_c - 1 downto 0)));
 
          incoming_channel_v := Incoming_data(src_i)(addr_width_c);
 
          resolved_dest_v := router_func (router_addr(src_i), router_id_g);
          curr_dst (src_i) <= resolved_dest_v;
 
          -- channel handling:
          -- if packet is going to fwd or rev directions and it's either coming
          -- trough channel 1 or this is the one router with datelines around it,
          -- we put the packet to channel 1
          if (resolved_dest_v = fwd_c or resolved_dest_v = rev_c)
            and (dateline_en_g = 1 or incoming_channel_v = '1')
          then
            curr_channel(src_i) <= 1;
          else
            curr_channel(src_i) <= 0;
          end if;
 
 
        else                            --1)
          -- No packet on curr src port or read operation already started
          curr_dst (src_i) <= no_dir_c;
          curr_channel (src_i) <= 0;
        end if;  -- State_reading_r
 
      end loop;  -- i
 
    end process Check_dst;
 
 
  -----------------------------------------------------------------------------
  resolve_conflicts : process (curr_dst, start_idx_r)
    variable hi_port_v : integer range 0 to n_ports_c;
    variable lo_port_v : integer range 0 to n_ports_c;
  begin  -- process resolve_conflicts
 
    curr_dst_resolved <= curr_dst;
 
    -- 1) Go through all destination ports
    -- 2) Use start_idx_r to separate high and low priotities
    -- 3) Give turn to inport with smallest id in high side, and if there's no
    -- requests there, inport with smallest id in low side
    for dst_i in 0 to n_ports_c-1 loop
      hi_port_v := no_dir_c;
      lo_port_v := no_dir_c;
 
      for src_i in 0 to n_ports_c-1 loop
 
        if curr_dst(src_i) = dst_i then
          -- src_i wants to send to dst_i
 
          if src_i > start_idx_r-1 then
            -- this is hi priority side
            if hi_port_v /= no_dir_c then
              curr_dst_resolved(src_i) <= no_dir_c;
            else
              hi_port_v := src_i;
            end if;
 
          else
            -- low priority side
 
            if lo_port_v /= no_dir_c then
              curr_dst_resolved(src_i) <= no_dir_c;
            else
              lo_port_v := src_i;
            end if;
 
          end if;
        end if;
      end loop;  -- src_i
 
      if hi_port_v /= no_dir_c and lo_port_v /= no_dir_c then
        curr_dst_resolved(lo_port_v) <= no_dir_c;
      end if;
 
    end loop;  -- dst_i
 
  end process resolve_conflicts;
 
 
  -----------------------------------------------------------------------------
  incr_start_idx : process (clk_net, rst_n)
  begin  -- process incr_start_idx
    if rst_n = '0' then                 -- asynchronous reset (active low)
      start_idx_r <= 0;
    elsif clk_net'event and clk_net = '1' then  -- rising clock edge
      if start_idx_r = n_ports_c-1 then
        start_idx_r <= 0;
      else
        start_idx_r <= start_idx_r +1;
      end if;
    end if;
  end process incr_start_idx;
 
 
  -------------------------------------------------------------------------------
  data_dbg : for i in 0 to n_ports_c-1 generate
    data_ctrl_fifo_dbg (i) <= data_ctrl_fifo_r (i) when data_reg_valid_r (i) = '1'
                              else (others => dbg_value_c(sim_dbg_ena_g));  --(others => 'Z');
  end generate data_dbg;
 
  -----------------------------------------------------------------------------
  -- enable channel 1
  out_channel: process (clk_net, rst_n)
  begin  -- process out_channel
    if rst_n = '0' then                 -- asynchronous reset (active low)
      fwd_chan_sel_r <= '0';
      rev_chan_sel_r <= '0';
      fwd_pkt_counter_r <= 0;
      rev_pkt_counter_r <= 0;
      fwd_pkt_len_r <= 0;
      rev_pkt_len_r <= 0;
 
    elsif clk_net'event and clk_net = '1' then  -- rising clock edge
 
      -- get the pkt length
      if state_src_r(fwd_c) /= no_dir_c then
        fwd_pkt_len_r <= pkt_len_arr_r(state_src_r(fwd_c));
      end if;
 
      -- if read enable is up, receiving router is reading a flit
      if re_fwd_in = '1' then
 
        -- last flit about to be read?
        if fwd_pkt_counter_r = fwd_pkt_len_r - 1 then
          fwd_pkt_counter_r <= 0;
        else
          fwd_pkt_counter_r <= fwd_pkt_counter_r + 1;
        end if;
 
      end if;
 
 
      -- if no packet is yet being sent or if one packet has
      -- just been completed, we can change the fifos
      if (fwd_pkt_counter_r = 0 and re_fwd_in = '0')
        or (fwd_pkt_counter_r = fwd_pkt_len_r - 1 and re_fwd_in = '1')
      then
 
        -- if fifo1 not empty, switch to it
        if empty_from_fwd1 = '0' then
          fwd_chan_sel_r <= '1';
        else
          -- falling back to channel 0
          fwd_chan_sel_r <= '0';
        end if;
 
      end if;
 
 
      -- same for the rev
      if state_src_r(rev_c) /= no_dir_c then
        rev_pkt_len_r <= pkt_len_arr_r(state_src_r(rev_c));
      end if;
 
      if re_rev_in = '1' then
 
        if rev_pkt_counter_r = rev_pkt_len_r - 1 then
          rev_pkt_counter_r <= 0;
        else
          rev_pkt_counter_r <= rev_pkt_counter_r + 1;
        end if;
      end if;
 
      if (rev_pkt_counter_r = 0 and re_rev_in = '0') or
        (rev_pkt_counter_r = rev_pkt_len_r - 1 and re_rev_in = '1')
      then
        -- if fifo1 not empty, switch to it
        if empty_from_rev1 = '0' then
          rev_chan_sel_r <= '1';
        else
          -- falling back to channel 0
          rev_chan_sel_r <= '0';
        end if;
      end if;
 
    end if;
  end process out_channel;
 
  -----------------------------------------------------------------------------
  Main_control : process (clk_net, rst_n)
  begin  -- process Main_control
    if rst_n = '0' then                 -- asynchronous reset (active low)
      for i in 0 to n_ports_c-1 loop
        data_ctrl_fifo_r (i) <= (others => '0');  --'0');
        send_counter_r (i)   <= 0;
        pkt_len_arr_r(i) <= pkt_len_g;
      end loop;  -- i
 
      we_ctrl_fifo_r  <= (others => '0');
      re_r            <= (others => '0');
      State_writing_r <= (others => '0');
      State_reading_r <= (others => '0');
      state_src_r     <= (others => no_dir_c);
      state_dst_r     <= (others => no_dir_c);
      state_channel_r <= (others => 0);
 
      data_reg_valid_r <= (others => '1');
 
      if stfwd_en_g = 1 then
        assert fifo_depth_g = pkt_len_g report "Store-and-forward assumes fifo_depth equal to packet_length" severity failure;
      end if;
 
    elsif clk_net'event and clk_net = '1' then  -- rising clock edge
 
 
      for i in 0 to n_ports_c-1 loop
        -- Handle all directions
 
 
        -- From now on, loop variable i refers to source port
 
        if State_reading_r (i) = '1' then
          -- Already reading from direction i 
 
          -- Use counters to enable cut-through switching.
          -- The same thing works also with store-and-forward switching
          if send_counter_r (i) = pkt_len_arr_r(i)
          then
            -- stop
 
            if full_from_fifo (state_dst_r (i)) = '0' then
 
              we_ctrl_fifo_r (state_dst_r (i)) <= '0';
              re_r (i)                         <= '0';
 
              State_writing_r (state_dst_r (i)) <= '0';
              State_reading_r (i)               <= '0';
              state_src_r (state_dst_r (i))     <= no_dir_c;
              state_dst_r (i)                   <= no_dir_c;
              --assert false report "Tx to north fifo completed" severity note;
              state_channel_r(state_dst_r(i))   <= 0;
 
              send_counter_r (i)                 <= 0;
              data_ctrl_fifo_r (state_dst_r (i)) <= (others => dbg_value_c(sim_dbg_ena_g));
              data_reg_valid_r (state_dst_r (i)) <= '0';
 
              pkt_len_arr_r(i) <= pkt_len_g;
 
            --assert state_dst_r(i)/=4 report "Stop" severity note;
            else
            --assert  state_dst_r(i)/=4 report "Wait until last data fits into fifo" severity note;
            end if;
 
          else
            -- Packet transfer not yet complete
            -- Continue transfer
            we_ctrl_fifo_r (state_dst_r (i)) <= '1';
 
            State_writing_r (state_dst_r (i)) <= State_writing_r (state_dst_r (i));
            State_reading_r (i)               <= State_reading_r (i);
            state_src_r (state_dst_r (i))     <= state_src_r (state_dst_r (i));
            state_dst_r (i)                   <= state_dst_r (i);
            state_channel_r (state_dst_r(i))  <= state_channel_r (state_dst_r (i));
            --assert false report "Tx to north fifo in progress" severity note;
 
 
            -- i = source
            if data_reg_valid_r (state_dst_r(i)) = '0' then
              -- data_reg empty
 
              if re_tmp (i) = '1' then
                data_reg_valid_r (state_dst_r(i))  <= '1';  -- read new value
                send_counter_r (i)                 <= send_counter_r (i) +1;
                data_ctrl_fifo_r (state_dst_r (i)) <= Incoming_data (i);
 
              else
                data_reg_valid_r (state_dst_r(i)) <= '0';  -- stay empty                
              end if;
 
            else
              -- data_reg full
 
              if full_from_fifo (state_dst_r (i)) = '0' then
                -- write old to fifo
                if re_tmp (i) = '1' then
                  data_reg_valid_r (state_dst_r(i))  <= '1';  -- write old, read new value
                  send_counter_r (i)                 <= send_counter_r (i) +1;
                  data_ctrl_fifo_r (state_dst_r (i)) <= Incoming_data (i);
                else
                  data_reg_valid_r (state_dst_r(i)) <= '0';  -- write old, now empty               
                end if;
 
              else
                -- cannot write old
                data_reg_valid_r (state_dst_r(i)) <= '1';
                assert re_tmp (i) = '0' report "reading not allowed now" severity error;
              end if;
 
            end if;
 
            -- if address hasn't been read, put in the channel bit
            if send_counter_r(i) = 0 then
              if state_channel_r(state_dst_r(i)) = 1 then
                data_ctrl_fifo_r(state_dst_r(i))(addr_width_c) <= '1';
              else
                data_ctrl_fifo_r(state_dst_r(i))(addr_width_c) <= '0';
              end if;
            end if;
 
 
            -- Reading the pkt length
            if len_flit_en_g = 0 and re_tmp(i) = '1' and send_counter_r(i) = 0 then
              -- +1 at the end: address flit
              pkt_len_arr_r(i) <= conv_integer( unsigned( Incoming_data(i)(data_width_g-1 downto data_width_g-len_width_c))) + 1;
            elsif len_flit_en_g = 1 and re_tmp(i) = '1' and send_counter_r(i) = 1 then
              -- +2: address and len flits
              pkt_len_arr_r(i) <= conv_integer( unsigned( Incoming_data(i) )) + 2;
            end if;
 
 
            -- Stop reading little bit earlier than writing stops
            if send_counter_r (i) = pkt_len_arr_r(i) - 1
              and Incoming_empty (i) = '0'  -- 2006/10/24
              and full_from_fifo (state_dst_r(i)) = '0'
            then
              re_r (i) <= '0';
            else
              re_r (i) <= '1';
            end if;
 
 
          end if;
 
        else
          -- Not yet reading from direction i 
 
          -- Direction i has to be current source,
          -- there must be valid address on port i
          -- and target fifo has to be empty (i.e. it is not full or reserved)
          -- also state_channel must match the curr_channel so that
          -- empty_from_fifo signal comes from the right fifo
          if                            -- curr_src_r = i and
            curr_dst_resolved (i) /= no_dir_c
            and empty_from_fifo (curr_dst_resolved (i)) = '1'
            and State_writing_r (curr_dst_resolved (i)) = '0'
            and curr_channel(i) = state_channel_r(curr_dst_resolved(i))
          then
            -- Start reading
 
            we_ctrl_fifo_r (curr_dst_resolved (i))  <= '0';
            -- WE not yet '1' because RE is just being asserted to one
            -- Otherwise, the first data (i.e.) would be written twice and the
            -- last data would be discarded
            State_writing_r (curr_dst_resolved (i)) <= '1';
 
            re_r (i)                              <= '1';
            State_reading_r (i)                   <= '1';
            state_src_r (curr_dst_resolved (i))   <= i;
            state_dst_r (i)                       <= curr_dst_resolved (i);
 
            send_counter_r (i)                       <= send_counter_r (i);  --??
            data_ctrl_fifo_r (curr_dst_resolved (i)) <= Incoming_data (i);
 
            -- if writing address, include the current channel bit
            if state_channel_r(curr_dst_resolved(i)) = 1 then
              data_ctrl_fifo_r(curr_dst_resolved(i))(addr_width_c) <= '1';
            else
              data_ctrl_fifo_r(curr_dst_resolved(i))(addr_width_c) <= '0';
            end if;
 
 
            data_reg_valid_r (curr_dst_resolved (i)) <= '1';
 
          --else
          -- Can't start reading from current source
          -- Do nothing
 
          end if;  --State_reading_r = i
 
          -- set the channel register when address is valid
          if curr_dst_resolved(i) /= no_dir_c
            and State_writing_r(curr_dst_resolved(i)) = '0'
          then
            state_channel_r(curr_dst_resolved(i)) <= curr_channel(i);
          end if;
 
        end if;  --State_reading_r(i)=1
 
      end loop;  -- i
 
    end if;  --Rst_n/Clk'event
  end process Main_control;
 
end rtl;
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.