1-------------------------------------------------------------------------------
2-- Title      : Simple Pipelined Wishbone MUX/DEMUX for WRPC
3-- Project    : WhiteRabbit
4-------------------------------------------------------------------------------
5-- File       : xwrf_mux.vhd
6-- Author     : Grzegorz Daniluk
7-- Company    : CERN BE-CO-HT
8-- Created    : 2011-08-11
9-- Last update: 2017-02-03
10-- Platform   : FPGA-generics
11-- Standard   : VHDL
12-------------------------------------------------------------------------------
13-- Description:
14-- This is the simple multiplexer/demultiplexer for WR Fabric interface
15-- (Pipelined Wishbone interface). It forwards ethernet frames between
16-- WR endpoint, Mini-NIC and external Fabric interface in both directions.
17-- In the direction 'from' WR endpoint it also decides whether the packet
18-- has to be forwarded to Mini-NIC (if it is the PTP message) or to the
19-- external interface (others).
20-------------------------------------------------------------------------------
21-- Copyright (c) 2012-2017 CERN
22--
23-- This source file is free software; you can redistribute it
24-- and/or modify it under the terms of the GNU Lesser General
25-- Public License as published by the Free Software Foundation;
26-- either version 2.1 of the License, or (at your option) any
27-- later version.
28--
29-- This source is distributed in the hope that it will be
30-- useful, but WITHOUT ANY WARRANTY; without even the implied
31-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
32-- PURPOSE.  See the GNU Lesser General Public License for more
33-- details.
34--
35-- You should have received a copy of the GNU Lesser General
36-- Public License along with this source; if not, download it
37-- from http://www.gnu.org/licenses/lgpl-2.1.html
38--
39-------------------------------------------------------------------------------
40-- Revisions  :
41-- Date        Version  Author          Description
42-- 2011-08-11  1.0      greg.d          Created
43-- 2012-10-16  2.0      greg.d          generic number of ports
44-------------------------------------------------------------------------------
45library ieee;
46use ieee.std_logic_1164.all;
47use ieee.std_logic_misc.all;
48
49use ieee.numeric_std.all;
50
51library work;
52use work.wr_fabric_pkg.all;
53use work.genram_pkg.all;
54
55entity xwrf_mux is
56  generic(
57    g_muxed_ports : integer := 2);
58  port(
59    clk_sys_i   : in  std_logic;
60    rst_n_i     : in  std_logic;
61    --ENDPOINT
62    ep_src_o    : out t_wrf_source_out;
63    ep_src_i    : in  t_wrf_source_in;
64    ep_snk_o    : out t_wrf_sink_out;
65    ep_snk_i    : in  t_wrf_sink_in;
66    --Muxed ports
67    mux_src_o   : out t_wrf_source_out_array(g_muxed_ports-1 downto 0);
68    mux_src_i   : in  t_wrf_source_in_array(g_muxed_ports-1 downto 0);
69    mux_snk_o   : out t_wrf_sink_out_array(g_muxed_ports-1 downto 0);
70    mux_snk_i   : in  t_wrf_sink_in_array(g_muxed_ports-1 downto 0);
71    --
72    mux_class_i : in  t_wrf_mux_class(g_muxed_ports-1 downto 0)
73    );
74end xwrf_mux;
75
76architecture behaviour of xwrf_mux is
77
78  function f_hot_to_bin(x : std_logic_vector(g_muxed_ports-1 downto 0))
79    return integer is
80    variable rv : integer;
81  begin
82    rv := 0;
83    -- if there are few ones set in _x_ then the least significant will be
84    -- translated to bin
85    for i in g_muxed_ports-1 downto 0 loop
86      if x(i) = '1' then
87        rv := i;
88      end if;
89    end loop;
90    return rv;
91  end function;
92
93  function f_match_class(port_mask, pkt_mask : std_logic_vector(7 downto 0)) return std_logic is
94    variable ret : std_logic;
95  begin
96    if((port_mask and pkt_mask) /= x"00") then
97      return '1';
98    else
99      return '0';
100    end if;
101  end function;
102
103  --==================================--
104  --  Masters to Endpoint mux signals --
105  --==================================--
106  type   t_mux is (MUX_SEL, MUX_TRANSFER);
107  signal mux        : t_mux;
108  signal mux_cycs   : std_logic_vector(g_muxed_ports-1 downto 0);
109  signal mux_rrobin : std_logic_vector(g_muxed_ports-1 downto 0);
110  signal mux_select : std_logic_vector(g_muxed_ports-1 downto 0);
111
112  --==================================--
113  -- Endpoint to Slaves demux signals --
114  --==================================--
115  type   t_demux is (DMUX_WAIT, DMUX_STATUS, DMUX_PAYLOAD);
116  signal demux            : t_demux;
117  signal dmux_sel         : std_logic_vector(g_muxed_ports-1 downto 0);
118  signal dmux_status_reg  : std_logic_vector(15 downto 0);
119  signal dmux_select      : std_logic_vector(g_muxed_ports-1 downto 0);
120  signal dmux_others      : std_logic_vector(g_muxed_ports-1 downto 0);
121  signal dmux_sel_zero    : std_logic;
122  signal dmux_snd_stat    : std_logic_vector(g_muxed_ports-1 downto 0);
123  signal ep_stall_mask    : std_logic;
124  signal ep_snk_out_stall : std_logic;
125
126begin
127
128  --=============================================--
129  --                                             --
130  --   Many Fabric Masters talking to ENDPOINT   --
131  --                                             --
132  --=============================================--
133  GEN_MUX_CYCS_REG : for I in 0 to g_muxed_ports-1 generate
134    mux_cycs(I) <= mux_snk_i(I).cyc;
135  end generate;
136
137  p_mux : process(clk_sys_i)
138  begin
139    if rising_edge(clk_sys_i) then
140      if (rst_n_i = '0') then
141        mux_rrobin(0)                        <= '1';
142        mux_rrobin(g_muxed_ports-1 downto 1) <= (others => '0');
143        mux                                  <= MUX_SEL;
144      else
145        case mux is
146          when MUX_SEL =>
147            if (unsigned(mux_cycs and mux_rrobin) /= 0)then
148              mux_select <= mux_cycs and mux_rrobin;
149              mux        <= MUX_TRANSFER;
150            else
151              mux_select <= (others => '0');
152              mux_rrobin <= mux_rrobin(0) & mux_rrobin(g_muxed_ports-1 downto 1);
153            end if;
154
155          when MUX_TRANSFER =>
156            if(unsigned(mux_cycs and mux_select) = 0) then  --cycle end
157              mux_rrobin <= mux_rrobin(0) & mux_rrobin(g_muxed_ports-1 downto 1);
158              mux        <= MUX_SEL;
159            end if;
160        end case;
161
162      end if;
163    end if;
164  end process;
165
166
167  GEN_MUX_CONNS : for J in 0 to g_muxed_ports-1 generate
168    mux_snk_o(J).ack <= ep_src_i.ack when(mux /= MUX_SEL and mux_select(J) = '1') else
169                        '0';
170    mux_snk_o(J).stall <= ep_src_i.stall when(mux /= MUX_SEL and mux_select(J) = '1') else
171                          '1';
172    mux_snk_o(J).err <= ep_src_i.err when(mux /= MUX_SEL and mux_select(J) = '1') else
173                        '0';
174    mux_snk_o(J).rty <= '0';
175  end generate;
176
177  ep_src_o.cyc <= mux_snk_i(f_hot_to_bin(mux_select)).cyc when(mux /= MUX_SEL) else
178                  '0';
179  ep_src_o.stb <= mux_snk_i(f_hot_to_bin(mux_select)).stb when(mux /= MUX_SEL) else
180                  '0';
181  ep_src_o.adr <= mux_snk_i(f_hot_to_bin(mux_select)).adr;
182  ep_src_o.dat <= mux_snk_i(f_hot_to_bin(mux_select)).dat;
183  ep_src_o.sel <= mux_snk_i(f_hot_to_bin(mux_select)).sel;
184  ep_src_o.we  <= '1';
185
186
187  --=============================================--
188  --                                             --
189  --    ENDPOINT talking to many Fabric Slaves   --
190  --                                             --
191  --=============================================--
192
193  CLASS_MATCH : for I in 0 to g_muxed_ports-1 generate
194    dmux_sel(I) <= f_match_class(mux_class_i(I), f_unmarshall_wrf_status(dmux_status_reg).match_class);
195  end generate;
196
197  DMUX_FSM : process(clk_sys_i)
198    variable sel : integer range 0 to g_muxed_ports-1;
199  begin
200    if rising_edge(clk_sys_i) then
201      if(rst_n_i = '0') then
202        dmux_select     <= (others => '0');
203        dmux_snd_stat   <= (others => '0');
204        dmux_status_reg <= (others => '0');
205        ep_stall_mask   <= '0';
206        demux           <= DMUX_WAIT;
207      else
208        case demux is
209                                        ---------------------------------------------------------------
210                                        --State DMUX_WAIT: Wait for the WRF cycle to start and then
211                                        --                 wait for the STATUS word
212                                        ---------------------------------------------------------------
213          when DMUX_WAIT =>
214            dmux_select     <= (others => '0');
215            dmux_snd_stat   <= (others => '0');
216            dmux_status_reg <= (others => '0');
217            ep_stall_mask   <= '0';
218            if(ep_snk_i.cyc = '1' and ep_snk_i.stb = '1' and ep_snk_i.adr = c_WRF_STATUS) then
219              ep_stall_mask   <= '1';
220              dmux_status_reg <= ep_snk_i.dat;
221              demux           <= DMUX_STATUS;
222            end if;
223
224                                        ---------------------------------------------------------------
225                                        --State DMUX_STATUS: Send Status word to appropriate interface
226                                        ---------------------------------------------------------------
227          when DMUX_STATUS =>
228            ep_stall_mask <= '1';
229
230            if(to_integer(unsigned(dmux_sel)) = 0) then  --class not matched to anything, pass pkt to last port
231              dmux_select(g_muxed_ports-1)   <= '1';
232              dmux_snd_stat(g_muxed_ports-1) <= '1';
233              sel                            := g_muxed_ports-1;
234            else
235              dmux_select   <= dmux_sel;
236              dmux_snd_stat <= dmux_sel;
237              sel           := f_hot_to_bin(dmux_sel);
238            end if;
239            if(mux_src_i(sel).stall = '0') then
240              demux <= DMUX_PAYLOAD;
241            end if;
242
243                                        ---------------------------------------------------------------
244                                        --State DMUX_PAYLOAD: Just wait here till the end of the
245                                        --                    current transfer
246                                        ---------------------------------------------------------------
247          when DMUX_PAYLOAD =>
248            dmux_snd_stat <= (others => '0');
249            ep_stall_mask <= '0';
250
251            if(ep_snk_i.cyc = '0') then
252              demux <= DMUX_WAIT;
253            end if;
254
255          when others =>
256            demux <= DMUX_WAIT;
257        end case;
258      end if;
259    end if;
260  end process;
261
262  dmux_sel_zero <= '1' when(to_integer(unsigned(dmux_select)) = 0) else
263                   '0';
264
265  -- dmux_others signal says for given interface I if any other interface was
266  -- also matched to packet class
267  dmux_others(0) <= '0';
268  GEN_DMUX_OTHERS : for I in 1 to g_muxed_ports-1 generate
269    dmux_others(I) <= or_reduce(dmux_select(I-1 downto 0));
270  end generate;
271
272
273  GEN_DMUX_CONN : for I in 0 to g_muxed_ports-1 generate
274    mux_src_o(I).cyc <= ep_snk_i.cyc when(dmux_select(I) = '1' and dmux_others(I) = '0') else
275                        '0';
276    mux_src_o(I).stb <= '1' when(dmux_snd_stat(I) = '1' and dmux_others(I) = '0') else
277                        ep_snk_i.stb when(dmux_select(I) = '1' and dmux_others(I) = '0') else
278                        '0';
279    mux_src_o(I).adr <= c_WRF_STATUS when(dmux_snd_stat(I) = '1' and dmux_others(I) = '0') else
280                        ep_snk_i.adr when(dmux_select(I) = '1' and dmux_others(I) = '0') else
281                        (others => '0');
282    mux_src_o(I).dat <= dmux_status_reg when(dmux_snd_stat(I) = '1' and dmux_others(I) = '0') else
283                        ep_snk_i.dat when(dmux_select(I) = '1' and dmux_others(I) = '0') else
284                        (others => '0');
285    mux_src_o(I).sel <= (others => '1') when(dmux_snd_stat(I) = '1' and dmux_others(I) = '0') else
286                        ep_snk_i.sel when(dmux_select(I) = '1' and dmux_others(I) = '0') else
287                        (others => '1');
288    mux_src_o(I).we <= '1';
289  end generate;
290
291
292  ep_snk_o.ack <= ep_snk_i.cyc and ep_snk_i.stb and not ep_snk_out_stall when(dmux_sel_zero = '1') else
293                  mux_src_i(f_hot_to_bin(dmux_select)).ack;
294
295  ep_snk_o.err <= '0' when(dmux_sel_zero = '1') else
296                  mux_src_i(f_hot_to_bin(dmux_select)).err;
297
298  ep_snk_out_stall <= '1' when(ep_stall_mask = '1') else
299                      '0' when(dmux_sel_zero = '1') else
300                      mux_src_i(f_hot_to_bin(dmux_select)).stall;
301
302  ep_snk_o.stall <= ep_snk_out_stall;
303
304  ep_snk_o.rty <= '0';
305
306end behaviour;
307
308