| 1 | 2 | danv | --------------------------------------------------------------------------------
 | 
      
         | 2 |  |  | --
 | 
      
         | 3 | 3 | danv | -- Copyright 2020
 | 
      
         | 4 | 2 | danv | -- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
 | 
      
         | 5 |  |  | -- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
 | 
      
         | 6 | 3 | danv | -- 
 | 
      
         | 7 |  |  | -- Licensed under the Apache License, Version 2.0 (the "License");
 | 
      
         | 8 |  |  | -- you may not use this file except in compliance with the License.
 | 
      
         | 9 |  |  | -- You may obtain a copy of the License at
 | 
      
         | 10 |  |  | -- 
 | 
      
         | 11 |  |  | --     http://www.apache.org/licenses/LICENSE-2.0
 | 
      
         | 12 |  |  | -- 
 | 
      
         | 13 |  |  | -- Unless required by applicable law or agreed to in writing, software
 | 
      
         | 14 |  |  | -- distributed under the License is distributed on an "AS IS" BASIS,
 | 
      
         | 15 |  |  | -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
      
         | 16 |  |  | -- See the License for the specific language governing permissions and
 | 
      
         | 17 |  |  | -- limitations under the License.
 | 
      
         | 18 | 2 | danv | --
 | 
      
         | 19 |  |  | --------------------------------------------------------------------------------
 | 
      
         | 20 |  |  |  
 | 
      
         | 21 |  |  | -- Purpose:
 | 
      
         | 22 |  |  | --   Multiplex frames from one or more input streams into one output stream.
 | 
      
         | 23 |  |  | -- Description:
 | 
      
         | 24 |  |  | --   The frames are marked by sop and eop. The input selection scheme depends
 | 
      
         | 25 |  |  | --   on g_mode:
 | 
      
         | 26 |  |  | --   0: Framed round-robin with fair chance.
 | 
      
         | 27 |  |  | --      Uses eop to select next input after the frame has been passed on or
 | 
      
         | 28 |  |  | --      select the next input when there is no frame coming in on the current
 | 
      
         | 29 |  |  | --      input, so it has had its chance.
 | 
      
         | 30 |  |  | --   1: Framed round-robin in forced order from each input.
 | 
      
         | 31 |  |  | --      Uses eop to select next output. Holds input selection until sop is
 | 
      
         | 32 |  |  | --      detected on that input. Results in ordered (low to high) but blocking
 | 
      
         | 33 |  |  | --      (on absence of sop) input selection.
 | 
      
         | 34 |  |  | --   2: Unframed external MM control input to select the output.
 | 
      
         | 35 |  |  | --      Three options have been considered for the flow control:
 | 
      
         | 36 |  |  | --      a) Use src_in for all inputs, data from the not selected inputs
 | 
      
         | 37 |  |  | --         will get lost. In case FIFOs are used they are only useful used for
 | 
      
         | 38 |  |  | --         the selected input.
 | 
      
         | 39 |  |  | --      b) Use c_dp_siso_rdy for unused inputs, this flushes them like with
 | 
      
         | 40 |  |  | --         option a) but possibly even faster in case the src_in.ready may get
 | 
      
         | 41 |  |  | --         inactive to apply backpressure.
 | 
      
         | 42 |  |  | --      c) Use c_dp_siso_hold for unused inputs, to stop them until they get
 | 
      
         | 43 |  |  | --         selected again.
 | 
      
         | 44 |  |  | --      Support only option a) because assume that the sel_ctrl is rather 
 | 
      
         | 45 |  |  | --      static and the data from the unused inputs can be ignored.
 | 
      
         | 46 |  |  | --   3: Framed external sel_ctrl input to select the output.
 | 
      
         | 47 |  |  | --      This scheme is identical to g_mode=0, but with xon='1' only for the 
 | 
      
         | 48 |  |  | --      selected input. The other not selected inputs have xon='0', so they
 | 
      
         | 49 |  |  | --      will stop getting input frames and the round-robin scheme of g_mode=0
 | 
      
         | 50 |  |  | --      will then automatically select only remaining active input.
 | 
      
         | 51 |  |  | --      The assumption is that the upstream input sources do stop their output
 | 
      
         | 52 |  |  | --      after they finished the current frame when xon='0'. If necessary
 | 
      
         | 53 |  |  | --      dp_xonoff could be used to add such frame flow control to an input
 | 
      
         | 54 |  |  | --      stream that does not yet support xon/xoff. But better use g_mode=4 
 | 
      
         | 55 |  |  | --      instead of g_mode=3, because the implementation of g_mode=4 is more
 | 
      
         | 56 |  |  | --      simple.
 | 
      
         | 57 |  |  | --   4) Framed external sel_ctrl input to select the output without ready.
 | 
      
         | 58 |  |  | --      This is preferred over g_mode=3 because it passes on the ready but
 | 
      
         | 59 |  |  | --      does not use it self. Not selected inputs have xon='0'. Only the
 | 
      
         | 60 |  |  | --      selected input has xon='1'. When sel_ctrl changes then briefly all
 | 
      
         | 61 |  |  | --      inputs get xon='0'. The new selected input only gets xon='1' when
 | 
      
         | 62 |  |  | --      the current selected input is idle or has become idle.
 | 
      
         | 63 |  |  | --       
 | 
      
         | 64 |  |  | --   The low part of the src_out.channel has c_sel_w = log2(g_nof_input) nof
 | 
      
         | 65 |  |  | --   bits and equals the input port number. The snk_in_arr().channel bits are
 | 
      
         | 66 |  |  | --   copied into the high part of the src_out.channel. Hence the total
 | 
      
         | 67 |  |  | --   effective output channel width becomes g_in_channel_w+c_sel_w when
 | 
      
         | 68 |  |  | --   g_use_in_channel=TRUE else c_sel_w.
 | 
      
         | 69 |  |  | --   If g_use_fifo=TRUE then the frames are buffered at the input, else the
 | 
      
         | 70 |  |  | --   connecting inputs need to take care of that.
 | 
      
         | 71 |  |  | -- Remark:
 | 
      
         | 72 |  |  | -- . Using g_nof_input=1 is transparent.
 | 
      
         | 73 |  |  | -- . Difference with dp_frame_scheduler is that dp_frame_scheduler does not
 | 
      
         | 74 |  |  | --   support back pressure via the ready signals.
 | 
      
         | 75 |  |  | -- . This dp_mux adds true_log2(nof ports) low bits to out_channel and the
 | 
      
         | 76 |  |  | --   dp_demux removes true_log2(nof ports) low bits from in_channel.
 | 
      
         | 77 |  |  | -- . For multiplexing time series frames or sample it can be applicable to
 | 
      
         | 78 |  |  | --   use g_append_channel_lo=FALSE in combination with g_mode=2.
 | 
      
         | 79 |  |  |  
 | 
      
         | 80 | 4 | danv | LIBRARY IEEE, common_pkg_lib, dp_pkg_lib, dp_components_lib, astron_fifo_lib;
 | 
      
         | 81 | 2 | danv | USE IEEE.std_logic_1164.ALL;
 | 
      
         | 82 |  |  | USE IEEE.numeric_std.ALL;
 | 
      
         | 83 |  |  | USE common_pkg_lib.common_pkg.ALL;
 | 
      
         | 84 |  |  | USE dp_pkg_lib.dp_stream_pkg.ALL;
 | 
      
         | 85 | 4 | danv | --USE technology_lib.technology_select_pkg.ALL;
 | 
      
         | 86 | 2 | danv |  
 | 
      
         | 87 |  |  | ENTITY dp_mux IS
 | 
      
         | 88 |  |  |   GENERIC (
 | 
      
         | 89 | 4 | danv |     g_technology        : NATURAL := 0; --c_tech_select_default;
 | 
      
         | 90 | 2 | danv |     -- MUX
 | 
      
         | 91 |  |  |     g_mode              : NATURAL := 0;
 | 
      
         | 92 |  |  |     g_nof_input         : NATURAL := 2;                   -- >= 1
 | 
      
         | 93 |  |  |     g_append_channel_lo : BOOLEAN := TRUE;
 | 
      
         | 94 |  |  |     g_sel_ctrl_invert   : BOOLEAN := FALSE;  -- Use default FALSE when stream array IO are indexed (0 TO g_nof_input-1), else use TRUE when indexed (g_nof_input-1 DOWNTO 0)
 | 
      
         | 95 |  |  |     -- Input FIFO
 | 
      
         | 96 |  |  |     g_use_fifo          : BOOLEAN := FALSE;
 | 
      
         | 97 |  |  |     g_bsn_w             : NATURAL := 16;
 | 
      
         | 98 |  |  |     g_data_w            : NATURAL := 16;
 | 
      
         | 99 |  |  |     g_empty_w           : NATURAL := 1;
 | 
      
         | 100 |  |  |     g_in_channel_w      : NATURAL := 1;
 | 
      
         | 101 |  |  |     g_error_w           : NATURAL := 1;
 | 
      
         | 102 |  |  |     g_use_bsn           : BOOLEAN := FALSE;
 | 
      
         | 103 |  |  |     g_use_empty         : BOOLEAN := FALSE;
 | 
      
         | 104 |  |  |     g_use_in_channel    : BOOLEAN := FALSE;
 | 
      
         | 105 |  |  |     g_use_error         : BOOLEAN := FALSE;
 | 
      
         | 106 |  |  |     g_use_sync          : BOOLEAN := FALSE;
 | 
      
         | 107 |  |  |     g_fifo_af_margin    : NATURAL := 4;  -- Nof words below max (full) at which fifo is considered almost full
 | 
      
         | 108 |  |  |     g_fifo_size         : t_natural_arr := array_init(1024, 2);  -- must match g_nof_input, even when g_use_fifo=FALSE
 | 
      
         | 109 |  |  |     g_fifo_fill         : t_natural_arr := array_init(   0, 2)   -- must match g_nof_input, even when g_use_fifo=FALSE
 | 
      
         | 110 |  |  |   );
 | 
      
         | 111 |  |  |   PORT (
 | 
      
         | 112 |  |  |     rst         : IN  STD_LOGIC;
 | 
      
         | 113 |  |  |     clk         : IN  STD_LOGIC;
 | 
      
         | 114 |  |  |     -- Control
 | 
      
         | 115 |  |  |     sel_ctrl    : IN  NATURAL RANGE 0 TO g_nof_input-1 := 0;  -- used by g_mode = 2, 3, 4
 | 
      
         | 116 |  |  |     -- ST sinks
 | 
      
         | 117 |  |  |     snk_out_arr : OUT t_dp_siso_arr(0 TO g_nof_input-1);
 | 
      
         | 118 |  |  |     snk_in_arr  : IN  t_dp_sosi_arr(0 TO g_nof_input-1);
 | 
      
         | 119 |  |  |     -- ST source
 | 
      
         | 120 |  |  |     src_in      : IN  t_dp_siso;
 | 
      
         | 121 |  |  |     src_out     : OUT t_dp_sosi
 | 
      
         | 122 |  |  |   );
 | 
      
         | 123 |  |  | END dp_mux;
 | 
      
         | 124 |  |  |  
 | 
      
         | 125 |  |  |  
 | 
      
         | 126 |  |  | ARCHITECTURE rtl OF dp_mux IS
 | 
      
         | 127 |  |  |  
 | 
      
         | 128 |  |  |   -- Convert unconstrained range (that starts at INTEGER'LEFT) to 0 TO g_nof_input-1 range
 | 
      
         | 129 |  |  |   CONSTANT c_fifo_fill  : t_natural_arr(0 TO g_nof_input-1) := g_fifo_fill;
 | 
      
         | 130 |  |  |   CONSTANT c_fifo_size  : t_natural_arr(0 TO g_nof_input-1) := g_fifo_size;
 | 
      
         | 131 |  |  |  
 | 
      
         | 132 |  |  |   -- The low part of src_out.channel is used to represent the input port and the high part of src_out.channel is copied from snk_in_arr().channel
 | 
      
         | 133 |  |  |   CONSTANT c_sel_w      : NATURAL := true_log2(g_nof_input);
 | 
      
         | 134 |  |  |  
 | 
      
         | 135 |  |  |   CONSTANT c_rl         : NATURAL := 1;
 | 
      
         | 136 |  |  |   SIGNAL tb_ready_reg   : STD_LOGIC_VECTOR(0 TO g_nof_input*(1+c_rl)-1);
 | 
      
         | 137 |  |  |  
 | 
      
         | 138 |  |  |   TYPE state_type IS (s_idle, s_output);
 | 
      
         | 139 |  |  |  
 | 
      
         | 140 |  |  |   SIGNAL state            : state_type;
 | 
      
         | 141 |  |  |   SIGNAL nxt_state        : state_type;
 | 
      
         | 142 |  |  |  
 | 
      
         | 143 |  |  |   SIGNAL i_snk_out_arr    : t_dp_siso_arr(0 TO g_nof_input-1);
 | 
      
         | 144 |  |  |  
 | 
      
         | 145 |  |  |   SIGNAL sel_ctrl_reg     : NATURAL RANGE 0 TO g_nof_input-1;
 | 
      
         | 146 |  |  |   SIGNAL nxt_sel_ctrl_reg : NATURAL;
 | 
      
         | 147 |  |  |   SIGNAL sel_ctrl_evt     : STD_LOGIC;
 | 
      
         | 148 |  |  |   SIGNAL nxt_sel_ctrl_evt : STD_LOGIC;
 | 
      
         | 149 |  |  |  
 | 
      
         | 150 |  |  |   SIGNAL in_sel           : NATURAL RANGE 0 TO g_nof_input-1;  -- input port low part of src_out.channel
 | 
      
         | 151 |  |  |   SIGNAL nxt_in_sel       : NATURAL;
 | 
      
         | 152 |  |  |   SIGNAL next_sel         : NATURAL;
 | 
      
         | 153 |  |  |  
 | 
      
         | 154 |  |  |   SIGNAL rd_siso_arr      : t_dp_siso_arr(0 TO g_nof_input-1);
 | 
      
         | 155 |  |  |   SIGNAL rd_sosi_arr      : t_dp_sosi_arr(0 TO g_nof_input-1);
 | 
      
         | 156 |  |  |   SIGNAL rd_sosi_busy_arr : STD_LOGIC_VECTOR(0 TO g_nof_input-1);
 | 
      
         | 157 |  |  |  
 | 
      
         | 158 |  |  |   SIGNAL hold_src_in_arr  : t_dp_siso_arr(0 TO g_nof_input-1);
 | 
      
         | 159 |  |  |   SIGNAL next_src_out_arr : t_dp_sosi_arr(0 TO g_nof_input-1);
 | 
      
         | 160 |  |  |   SIGNAL pend_src_out_arr : t_dp_sosi_arr(0 TO g_nof_input-1);  -- SOSI control
 | 
      
         | 161 |  |  |  
 | 
      
         | 162 |  |  |   SIGNAL in_xon_arr       : STD_LOGIC_VECTOR(0 TO g_nof_input-1);
 | 
      
         | 163 |  |  |   SIGNAL nxt_in_xon_arr   : STD_LOGIC_VECTOR(0 TO g_nof_input-1);
 | 
      
         | 164 |  |  |  
 | 
      
         | 165 |  |  |   SIGNAL prev_src_in      : t_dp_siso;
 | 
      
         | 166 |  |  |   SIGNAL src_out_hi       : t_dp_sosi;  -- snk_in_arr().channel as high part of src_out.channel
 | 
      
         | 167 |  |  |   SIGNAL nxt_src_out_hi   : t_dp_sosi;
 | 
      
         | 168 |  |  |   SIGNAL channel_lo       : STD_LOGIC_VECTOR(c_sel_w-1 DOWNTO 0);
 | 
      
         | 169 |  |  |   SIGNAL nxt_channel_lo   : STD_LOGIC_VECTOR(c_sel_w-1 DOWNTO 0);
 | 
      
         | 170 |  |  |  
 | 
      
         | 171 |  |  | BEGIN
 | 
      
         | 172 |  |  |  
 | 
      
         | 173 |  |  |   snk_out_arr <= i_snk_out_arr;
 | 
      
         | 174 |  |  |  
 | 
      
         | 175 |  |  |   -- Monitor sink valid input and sink ready output
 | 
      
         | 176 |  |  |   proc_dp_siso_alert(clk, snk_in_arr, i_snk_out_arr, tb_ready_reg);
 | 
      
         | 177 |  |  |  
 | 
      
         | 178 |  |  |   p_src_out_wires : PROCESS(src_out_hi, channel_lo)
 | 
      
         | 179 |  |  |   BEGIN
 | 
      
         | 180 |  |  |     -- SOSI
 | 
      
         | 181 |  |  |     src_out <= src_out_hi;
 | 
      
         | 182 |  |  |  
 | 
      
         | 183 |  |  |     IF g_append_channel_lo=TRUE THEN
 | 
      
         | 184 |  |  |       -- The high part of src_out.channel copies the snk_in_arr().channel, the low part of src_out.channel is used to indicate the input port
 | 
      
         | 185 |  |  |       src_out.channel                     <= SHIFT_UVEC(src_out_hi.channel, -c_sel_w);
 | 
      
         | 186 |  |  |       src_out.channel(c_sel_w-1 DOWNTO 0) <= channel_lo;
 | 
      
         | 187 |  |  |     END IF;
 | 
      
         | 188 |  |  |   END PROCESS;
 | 
      
         | 189 |  |  |  
 | 
      
         | 190 |  |  |   p_clk: PROCESS(clk, rst)
 | 
      
         | 191 |  |  |   BEGIN
 | 
      
         | 192 |  |  |     IF rst='1' THEN
 | 
      
         | 193 |  |  |       sel_ctrl_reg <= 0;
 | 
      
         | 194 |  |  |       sel_ctrl_evt <= '0';
 | 
      
         | 195 |  |  |       in_xon_arr   <= (OTHERS=>'0');
 | 
      
         | 196 |  |  |       in_sel       <= 0;
 | 
      
         | 197 |  |  |       prev_src_in  <= c_dp_siso_rst;
 | 
      
         | 198 |  |  |       state        <= s_idle;
 | 
      
         | 199 |  |  |       src_out_hi   <= c_dp_sosi_rst;
 | 
      
         | 200 |  |  |       channel_lo   <= (OTHERS=>'0');
 | 
      
         | 201 |  |  |     ELSIF rising_edge(clk) THEN
 | 
      
         | 202 |  |  |       sel_ctrl_reg <= nxt_sel_ctrl_reg;
 | 
      
         | 203 |  |  |       sel_ctrl_evt <= nxt_sel_ctrl_evt;
 | 
      
         | 204 |  |  |       in_xon_arr   <= nxt_in_xon_arr;
 | 
      
         | 205 |  |  |       in_sel       <= nxt_in_sel;
 | 
      
         | 206 |  |  |       prev_src_in  <= src_in;
 | 
      
         | 207 |  |  |       state        <= nxt_state;
 | 
      
         | 208 |  |  |       src_out_hi   <= nxt_src_out_hi;
 | 
      
         | 209 |  |  |       channel_lo   <= nxt_channel_lo;
 | 
      
         | 210 |  |  |     END IF;
 | 
      
         | 211 |  |  |   END PROCESS;
 | 
      
         | 212 |  |  |  
 | 
      
         | 213 |  |  |   gen_input : FOR I IN 0 TO g_nof_input-1 GENERATE
 | 
      
         | 214 |  |  |     gen_fifo : IF g_use_fifo=TRUE GENERATE
 | 
      
         | 215 | 4 | danv |       u_fill : ENTITY astron_fifo_lib.dp_fifo_fill
 | 
      
         | 216 | 2 | danv |       GENERIC MAP (
 | 
      
         | 217 |  |  |         g_technology     => g_technology,
 | 
      
         | 218 |  |  |         g_bsn_w          => g_bsn_w,
 | 
      
         | 219 |  |  |         g_data_w         => g_data_w,
 | 
      
         | 220 |  |  |         g_empty_w        => g_empty_w,
 | 
      
         | 221 |  |  |         g_channel_w      => g_in_channel_w,
 | 
      
         | 222 |  |  |         g_error_w        => g_error_w,
 | 
      
         | 223 |  |  |         g_use_bsn        => g_use_bsn,
 | 
      
         | 224 |  |  |         g_use_empty      => g_use_empty,
 | 
      
         | 225 |  |  |         g_use_channel    => g_use_in_channel,
 | 
      
         | 226 |  |  |         g_use_error      => g_use_error,
 | 
      
         | 227 |  |  |         g_use_sync       => g_use_sync,
 | 
      
         | 228 |  |  |         g_fifo_fill      => c_fifo_fill(I),
 | 
      
         | 229 |  |  |         g_fifo_size      => c_fifo_size(I),
 | 
      
         | 230 |  |  |         g_fifo_af_margin => g_fifo_af_margin,
 | 
      
         | 231 |  |  |         g_fifo_rl        => 1
 | 
      
         | 232 |  |  |       )
 | 
      
         | 233 |  |  |       PORT MAP (
 | 
      
         | 234 |  |  |         rst      => rst,
 | 
      
         | 235 |  |  |         clk      => clk,
 | 
      
         | 236 |  |  |         -- ST sink
 | 
      
         | 237 |  |  |         snk_out  => i_snk_out_arr(I),
 | 
      
         | 238 |  |  |         snk_in   => snk_in_arr(I),
 | 
      
         | 239 |  |  |         -- ST source
 | 
      
         | 240 |  |  |         src_in   => rd_siso_arr(I),
 | 
      
         | 241 |  |  |         src_out  => rd_sosi_arr(I)
 | 
      
         | 242 |  |  |       );
 | 
      
         | 243 |  |  |     END GENERATE;
 | 
      
         | 244 |  |  |     no_fifo : IF g_use_fifo=FALSE GENERATE
 | 
      
         | 245 |  |  |       i_snk_out_arr <= rd_siso_arr;
 | 
      
         | 246 |  |  |       rd_sosi_arr   <= snk_in_arr;
 | 
      
         | 247 |  |  |     END GENERATE;
 | 
      
         | 248 |  |  |  
 | 
      
         | 249 |  |  |     -- Hold the sink input to be able to register the source output
 | 
      
         | 250 |  |  |     u_hold : ENTITY dp_components_lib.dp_hold_input
 | 
      
         | 251 |  |  |     PORT MAP (
 | 
      
         | 252 |  |  |       rst          => rst,
 | 
      
         | 253 |  |  |       clk          => clk,
 | 
      
         | 254 |  |  |       -- ST sink
 | 
      
         | 255 |  |  |       snk_out      => OPEN,                 -- SISO ready
 | 
      
         | 256 |  |  |       snk_in       => rd_sosi_arr(I),       -- SOSI
 | 
      
         | 257 |  |  |       -- ST source
 | 
      
         | 258 |  |  |       src_in       => hold_src_in_arr(I),   -- SISO ready
 | 
      
         | 259 |  |  |       next_src_out => next_src_out_arr(I),  -- SOSI
 | 
      
         | 260 |  |  |       pend_src_out => pend_src_out_arr(I),
 | 
      
         | 261 |  |  |       src_out_reg  => src_out_hi
 | 
      
         | 262 |  |  |     );
 | 
      
         | 263 |  |  |   END GENERATE;
 | 
      
         | 264 |  |  |  
 | 
      
         | 265 |  |  |   -- Register and adjust external MM sel_ctrl for g_sel_ctrl_invert
 | 
      
         | 266 |  |  |   nxt_sel_ctrl_reg <= sel_ctrl WHEN g_sel_ctrl_invert=FALSE ELSE g_nof_input-1-sel_ctrl;
 | 
      
         | 267 |  |  |  
 | 
      
         | 268 |  |  |   -- Detect change in sel_ctrl
 | 
      
         | 269 |  |  |   nxt_sel_ctrl_evt <= '1' WHEN nxt_sel_ctrl_reg/=sel_ctrl_reg ELSE '0';
 | 
      
         | 270 |  |  |  
 | 
      
         | 271 |  |  |   -- The output register stage matches RL = 1 for src_in.ready
 | 
      
         | 272 |  |  |   nxt_src_out_hi <= next_src_out_arr(in_sel);  -- default output selected next_src_out_arr 
 | 
      
         | 273 |  |  |   nxt_channel_lo <= TO_UVEC(in_sel, c_sel_w);  -- pass on input index via channel low
 | 
      
         | 274 |  |  |  
 | 
      
         | 275 |  |  |   ------------------------------------------------------------------------------
 | 
      
         | 276 |  |  |   -- Unframed MM controlled input selection scheme
 | 
      
         | 277 |  |  |   ------------------------------------------------------------------------------
 | 
      
         | 278 |  |  |  
 | 
      
         | 279 |  |  |   gen_sel_ctrl_direct : IF g_mode=2 GENERATE
 | 
      
         | 280 |  |  |     hold_src_in_arr <= (OTHERS=>src_in);  -- pass src_in on to all inputs, only the selected input sosi gets used and the sosi from the other inputs will get lost
 | 
      
         | 281 |  |  |     rd_siso_arr     <= (OTHERS=>src_in);
 | 
      
         | 282 |  |  |  
 | 
      
         | 283 |  |  |     nxt_in_sel <= sel_ctrl_reg;  -- external MM control selects the input
 | 
      
         | 284 |  |  |   END GENERATE;
 | 
      
         | 285 |  |  |  
 | 
      
         | 286 |  |  |   ------------------------------------------------------------------------------
 | 
      
         | 287 |  |  |   -- Framed input selection schemes
 | 
      
         | 288 |  |  |   ------------------------------------------------------------------------------
 | 
      
         | 289 |  |  |  
 | 
      
         | 290 |  |  |   gen_sel_ctrl_framed : IF g_mode=4 GENERATE
 | 
      
         | 291 |  |  |     u_dp_frame_busy_arr : ENTITY work.dp_frame_busy_arr
 | 
      
         | 292 |  |  |     GENERIC MAP (
 | 
      
         | 293 |  |  |       g_nof_inputs => g_nof_input,
 | 
      
         | 294 |  |  |       g_pipeline   => 1   -- register snk_in_busy to ease timing closure
 | 
      
         | 295 |  |  |     )
 | 
      
         | 296 |  |  |     PORT MAP (
 | 
      
         | 297 |  |  |       rst             => rst,
 | 
      
         | 298 |  |  |       clk             => clk,
 | 
      
         | 299 |  |  |       snk_in_arr      => rd_sosi_arr,
 | 
      
         | 300 |  |  |       snk_in_busy_arr => rd_sosi_busy_arr
 | 
      
         | 301 |  |  |     );
 | 
      
         | 302 |  |  |  
 | 
      
         | 303 |  |  |     hold_src_in_arr <= (OTHERS=>c_dp_siso_rdy);  -- effectively bypass the dp_hold_input
 | 
      
         | 304 |  |  |  
 | 
      
         | 305 |  |  |     p_rd_siso_arr : PROCESS(src_in, in_xon_arr)
 | 
      
         | 306 |  |  |     BEGIN
 | 
      
         | 307 |  |  |       FOR I IN 0 TO g_nof_input-1 LOOP
 | 
      
         | 308 |  |  |         rd_siso_arr(I).ready <= src_in.ready;    -- default pass on src_in ready flow control to all inputs
 | 
      
         | 309 |  |  |         rd_siso_arr(I).xon   <= in_xon_arr(I);   -- use xon to enable one input and stop all other inputs
 | 
      
         | 310 |  |  |       END LOOP;
 | 
      
         | 311 |  |  |     END PROCESS;
 | 
      
         | 312 |  |  |  
 | 
      
         | 313 |  |  |     p_state : PROCESS(state, in_sel, rd_sosi_busy_arr, sel_ctrl_reg, sel_ctrl_evt)
 | 
      
         | 314 |  |  |     BEGIN
 | 
      
         | 315 |  |  |       nxt_state      <= state;
 | 
      
         | 316 |  |  |       nxt_in_sel     <= in_sel;
 | 
      
         | 317 |  |  |       nxt_in_xon_arr <= (OTHERS=>'0');  -- Default stop all inputs
 | 
      
         | 318 |  |  |  
 | 
      
         | 319 |  |  |       CASE state IS
 | 
      
         | 320 |  |  |         WHEN s_idle =>
 | 
      
         | 321 |  |  |           -- Wait until all inputs are inactive (due to xon='0') to ensure that the old input has finished its last frame and the new input has not started yet
 | 
      
         | 322 |  |  |           IF UNSIGNED(rd_sosi_busy_arr)=0 THEN
 | 
      
         | 323 |  |  |             nxt_in_sel <= sel_ctrl_reg;
 | 
      
         | 324 |  |  |             nxt_state <= s_output;
 | 
      
         | 325 |  |  |           END IF;
 | 
      
         | 326 |  |  |  
 | 
      
         | 327 |  |  |         WHEN OTHERS => -- s_output
 | 
      
         | 328 |  |  |           -- Enable only the selected input via xon='1'
 | 
      
         | 329 |  |  |           nxt_in_xon_arr(sel_ctrl_reg) <= '1';
 | 
      
         | 330 |  |  |  
 | 
      
         | 331 |  |  |           -- Detect if the input selection changes
 | 
      
         | 332 |  |  |           IF sel_ctrl_evt='1' THEN
 | 
      
         | 333 |  |  |             nxt_state <= s_idle;
 | 
      
         | 334 |  |  |           END IF;
 | 
      
         | 335 |  |  |       END CASE;
 | 
      
         | 336 |  |  |     END PROCESS;
 | 
      
         | 337 |  |  |   END GENERATE;
 | 
      
         | 338 |  |  |  
 | 
      
         | 339 |  |  |  
 | 
      
         | 340 |  |  |   gen_framed : IF g_mode=0 OR g_mode=1 OR g_mode=3 GENERATE
 | 
      
         | 341 |  |  |     p_hold_src_in_arr : PROCESS(rd_siso_arr, pend_src_out_arr, in_sel, src_in)
 | 
      
         | 342 |  |  |     BEGIN
 | 
      
         | 343 |  |  |       hold_src_in_arr <= rd_siso_arr;       -- default ready for hold input when ready for sink input
 | 
      
         | 344 |  |  |       IF pend_src_out_arr(in_sel).eop='1' THEN
 | 
      
         | 345 |  |  |         hold_src_in_arr(in_sel) <= src_in;  -- also ready for hold input when the eop is there
 | 
      
         | 346 |  |  |       END IF;
 | 
      
         | 347 |  |  |     END PROCESS;
 | 
      
         | 348 |  |  |  
 | 
      
         | 349 |  |  |     next_sel <= in_sel+1 WHEN in_sel<g_nof_input-1 ELSE 0;
 | 
      
         | 350 |  |  |  
 | 
      
         | 351 |  |  |     p_state : PROCESS(state, in_sel, next_sel, pend_src_out_arr, src_in, prev_src_in, sel_ctrl_reg)
 | 
      
         | 352 |  |  |     BEGIN
 | 
      
         | 353 |  |  |       rd_siso_arr <= (OTHERS=>c_dp_siso_hold);  -- default not ready for input, but xon='1'
 | 
      
         | 354 |  |  |  
 | 
      
         | 355 |  |  |       nxt_in_sel <= in_sel;
 | 
      
         | 356 |  |  |  
 | 
      
         | 357 |  |  |       nxt_state <= state;
 | 
      
         | 358 |  |  |  
 | 
      
         | 359 |  |  |       CASE state IS
 | 
      
         | 360 |  |  |         WHEN s_idle =>
 | 
      
         | 361 |  |  |           -- Need to check pend_src_out_arr(in_sel).sop, which can be active if prev_src_in.ready was '1',
 | 
      
         | 362 |  |  |           -- because src_in.ready may be '0' and then next_src_out_arr(in_sel).sop is '0'
 | 
      
         | 363 |  |  |           IF pend_src_out_arr(in_sel).sop='1' THEN
 | 
      
         | 364 |  |  |             IF pend_src_out_arr(in_sel).eop='1' THEN
 | 
      
         | 365 |  |  |               rd_siso_arr <= (OTHERS=>c_dp_siso_hold);  -- the sop and the eop are there, it is a frame with only one data word, stop reading this input
 | 
      
         | 366 |  |  |               IF src_in.ready='1' THEN
 | 
      
         | 367 |  |  |                 nxt_in_sel            <= next_sel;      -- the pend_src_out_arr(in_sel).eop will be output, so continue to next input.
 | 
      
         | 368 |  |  |                 rd_siso_arr(next_sel) <= src_in;
 | 
      
         | 369 |  |  |               END IF;
 | 
      
         | 370 |  |  |             ELSE
 | 
      
         | 371 |  |  |               rd_siso_arr(in_sel) <= src_in;            -- the sop is there, so start outputting the frame from this input
 | 
      
         | 372 |  |  |               nxt_state <= s_output;
 | 
      
         | 373 |  |  |             END IF;
 | 
      
         | 374 |  |  |           ELSE
 | 
      
         | 375 |  |  |             CASE g_mode IS
 | 
      
         | 376 |  |  |               WHEN 0 | 3 =>
 | 
      
         | 377 |  |  |                 -- Framed round-robin with fair chance per input
 | 
      
         | 378 |  |  |                 IF prev_src_in.ready='0' THEN
 | 
      
         | 379 |  |  |                   rd_siso_arr(in_sel) <= src_in;        -- no sop, remain at current input to give it a chance
 | 
      
         | 380 |  |  |                 ELSE
 | 
      
         | 381 |  |  |                   nxt_in_sel            <= next_sel;    -- no sop, select next input, because the current input has had a chance
 | 
      
         | 382 |  |  |                   rd_siso_arr(next_sel) <= src_in;
 | 
      
         | 383 |  |  |                 END IF;
 | 
      
         | 384 |  |  |               WHEN OTHERS =>  -- = 1
 | 
      
         | 385 |  |  |                 -- Framed round-robin in forced order from each input
 | 
      
         | 386 |  |  |                 rd_siso_arr(in_sel) <= src_in;          -- no sop, remain at current input to wait for a frame     
 | 
      
         | 387 |  |  |             END CASE;
 | 
      
         | 388 |  |  |           END IF;
 | 
      
         | 389 |  |  |         WHEN OTHERS => -- s_output
 | 
      
         | 390 |  |  |           rd_siso_arr(in_sel) <= src_in;                -- output the rest of the selected input frame
 | 
      
         | 391 |  |  |           IF pend_src_out_arr(in_sel).eop='1' THEN
 | 
      
         | 392 |  |  |             rd_siso_arr <= (OTHERS=>c_dp_siso_hold);    -- the eop is there, stop reading this input
 | 
      
         | 393 |  |  |             IF src_in.ready='1' THEN
 | 
      
         | 394 |  |  |               nxt_in_sel            <= next_sel;        -- the pend_src_out_arr(in_sel).eop will be output, so continue to next input. 
 | 
      
         | 395 |  |  |               rd_siso_arr(next_sel) <= src_in;
 | 
      
         | 396 |  |  |               nxt_state <= s_idle;
 | 
      
         | 397 |  |  |             END IF;
 | 
      
         | 398 |  |  |           END IF;
 | 
      
         | 399 |  |  |       END CASE;
 | 
      
         | 400 |  |  |  
 | 
      
         | 401 |  |  |       -- Pass on frame level flow control
 | 
      
         | 402 |  |  |       FOR I IN 0 TO g_nof_input-1 LOOP
 | 
      
         | 403 |  |  |         rd_siso_arr(I).xon <= src_in.xon;
 | 
      
         | 404 |  |  |  
 | 
      
         | 405 |  |  |         IF g_mode=3 THEN
 | 
      
         | 406 |  |  |           -- Framed MM control select input via XON
 | 
      
         | 407 |  |  |           rd_siso_arr(I).xon <= '0';            -- force xon='0' for not selected inputs
 | 
      
         | 408 |  |  |           IF sel_ctrl_reg=I THEN
 | 
      
         | 409 |  |  |             rd_siso_arr(I).xon <= src_in.xon;   -- pass on frame level flow control for selected input
 | 
      
         | 410 |  |  |           END IF;
 | 
      
         | 411 |  |  |         END IF;
 | 
      
         | 412 |  |  |       END LOOP;
 | 
      
         | 413 |  |  |     END PROCESS;
 | 
      
         | 414 |  |  |  
 | 
      
         | 415 |  |  |   END GENERATE;
 | 
      
         | 416 |  |  |  
 | 
      
         | 417 |  |  | END rtl;
 |