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

Subversion Repositories astron_multiplexer

[/] [astron_multiplexer/] [trunk/] [dp_mux.vhd] - Blame information for rev 4

Details | Compare with Previous | View Log

Line No. Rev Author Line
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;

powered by: WebSVN 2.1.0

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