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.interface/] [udp2hibi/] [1.0/] [vhd/] [rx_ctrl.vhd] - Blame information for rev 157

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 145 lanttu
-------------------------------------------------------------------------------
2
-- Title      : Rx control
3
-- Project    : UDP2HIBI
4
-------------------------------------------------------------------------------
5
-- File       : rx_ctrl.vhd
6
-- Author     : Jussi Nieminen
7
-- Last update: 2012-03-23
8
-- Platform   : 
9
-------------------------------------------------------------------------------
10
-- Description: Sub-block of udp2hibi.
11
--              Receives data from UDP/IP. Gives parameters from ctrl-regs
12
--              and gives data to hibi_transmitter. Includes both
13
--              multiclk-fifo and regular fifo and 2 state machines.
14
-------------------------------------------------------------------------------
15
-- Revisions  :
16
-- Date        Version  Author          Description
17
-- 2009/12/16  1.0      niemin95        Created
18
-- 2012-03-23  1.0      ege             Beautifying and commenting.
19
-------------------------------------------------------------------------------
20
 
21
library ieee;
22
use ieee.std_logic_1164.all;
23
use ieee.numeric_std.all;
24
use work.udp2hibi_pkg.all;
25
 
26
 
27
 
28
entity rx_ctrl is
29
 
30
  generic (
31
    rx_multiclk_fifo_depth_g : integer := 10;
32
    tx_fifo_depth_g          : integer := 10;
33
    hibi_data_width_g        : integer := 32;  -- bits. do not change
34
    frequency_g              : integer := 50000000
35
    );
36
 
37
  port (
38
    clk              : in  std_logic;
39
    clk_udp          : in  std_logic;
40
    rst_n            : in  std_logic;
41
    -- from UDP/IP
42
    rx_data_in       : in  std_logic_vector(udp_block_data_w_c-1 downto 0);
43
    rx_data_valid_in : in  std_logic;
44
    rx_re_out        : out std_logic;
45
    new_rx_in        : in  std_logic;
46
    rx_len_in        : in  std_logic_vector(tx_len_w_c-1 downto 0);
47
    source_ip_in     : in  std_logic_vector(ip_addr_w_c-1 downto 0);
48
    dest_port_in     : in  std_logic_vector(udp_port_w_c-1 downto 0);
49
    source_port_in   : in  std_logic_vector(udp_port_w_c-1 downto 0);
50
    rx_erroneous_in  : in  std_logic;
51
    -- to/from ctrl regs
52
    ip_out           : out std_logic_vector(ip_addr_w_c-1 downto 0);
53
    dest_port_out    : out std_logic_vector(udp_port_w_c-1 downto 0);
54
    source_port_out  : out std_logic_vector(udp_port_w_c-1 downto 0);
55
    rx_addr_valid_in : in  std_logic;
56
    -- to/from hibi_transmitter
57
    send_request_out : out std_logic;
58
    rx_len_out       : out std_logic_vector(tx_len_w_c-1 downto 0);
59
    ready_for_tx_in  : in  std_logic;
60
    rx_empty_out     : out std_logic;
61
    rx_data_out      : out std_logic_vector(hibi_data_width_g-1 downto 0);
62
    rx_re_in         : in  std_logic
63
    );
64
 
65
end rx_ctrl;
66
 
67
 
68
architecture rtl of rx_ctrl is
69
 
70
  component multiclk_fifo
71
    generic (
72
      re_freq_g    : integer;
73
      we_freq_g    : integer;
74
      depth_g      : integer;
75
      data_width_g : integer);
76
    port (
77
      clk_re    : in  std_logic;
78
      clk_we    : in  std_logic;
79
      rst_n     : in  std_logic;
80
      data_in   : in  std_logic_vector (data_width_g-1 downto 0);
81
      we_in     : in  std_logic;
82
      full_out  : out std_logic;
83
      one_p_out : out std_logic;
84
      re_in     : in  std_logic;
85
      data_out  : out std_logic_vector (data_width_g-1 downto 0);
86
      empty_out : out std_logic;
87
      one_d_out : out std_logic);
88
  end component;
89
 
90
  component fifo
91
    generic (
92
      data_width_g : integer;
93
      depth_g      : integer);
94
    port (
95
      clk       : in  std_logic;
96
      rst_n     : in  std_logic;
97
      data_in   : in  std_logic_vector (data_width_g-1 downto 0);
98
      we_in     : in  std_logic;
99
      full_out  : out std_logic;
100
      one_p_out : out std_logic;
101
      re_in     : in  std_logic;
102
      data_out  : out std_logic_vector (data_width_g-1 downto 0);
103
      empty_out : out std_logic;
104
      one_d_out : out std_logic);
105
  end component;
106
 
107
  signal we_to_multiclk_fifo      : std_logic;
108
  signal data_from_multiclk_fifo  : std_logic_vector(udp_block_data_w_c-1 downto 0);
109
  signal empty_from_multiclk_fifo : std_logic;
110
  signal full_from_multiclk_fifo  : std_logic;
111
  signal re_to_multiclk_fifo      : std_logic;
112
  signal data_to_tx_fifo          : std_logic_vector(hibi_data_width_g-1 downto 0);
113
  signal we_to_tx_fifo            : std_logic;
114
  signal full_from_tx_fifo        : std_logic;
115
  signal empty_for_tx_we          : std_logic;
116
 
117
  -- Counter that keeps track of how much data there still is to be written to
118
  -- the tx fifo
119
  signal tx_data_cnt_r        : integer range 0 to 2**(tx_len_w_c-1)-1;
120
  signal multiclk_re_r        : std_logic;
121
  signal lower_half_r         : std_logic_vector(udp_block_data_w_c-1 downto 0);
122
  signal read_upper_half_r    : std_logic;
123
  signal udp_re_multiclk_we_r : std_logic;
124
 
125
  -- Fifo glue means the logic between those two fifos...
126
  -- multclkfifo -> glue -> fifo
127
  type   fifo_glue_state_type is (idle, working, dumping);
128
  signal fifo_glue_state_r : fifo_glue_state_type;
129
 
130
  signal activate_fifo_glue_r : std_logic;
131
 
132
  -- rx len will be in halfwords
133
  signal rx_len_r             : integer range 0 to 2**(tx_len_w_c-1)-1;
134
  -- this len will be in bytes, and it's just forwarded to hibi transmitter
135
  signal rx_len_for_ht_r      : std_logic_vector(tx_len_w_c-1 downto 0);
136
 
137
 
138
  signal prevent_read_r       : std_logic;
139
  signal new_rx_old_r         : std_logic;
140
  signal dump_rx_r            : std_logic;
141
  signal rx_erroneous_r       : std_logic;
142
 
143
  -- Rx ctrl main state machine
144
  type   rx_ctrl_state_type is (wait_rx, wait_address, check_address);
145
  signal rx_ctrl_state_r : rx_ctrl_state_type;
146
 
147
  signal rx_data_valid_old_r : std_logic;
148
 
149
-------------------------------------------------------------------------------
150
begin  -- rtl
151
-------------------------------------------------------------------------------
152
 
153
  -- 
154
  --             +-------------------------------------------+  
155
  --             |                                           |
156
  --  udp/ip  ------->  multiclk fifo  --> glue  --> fifo  ---> hibi
157
  --             |  |       /                                |
158
  --             |  +->  main                                |
159
  --             |        |                                  |
160
  --  ctrl regs <---------+                                  |
161
  --             |                                           |
162
  --             +-------------------------------------------+  
163
  -- 
164
 
165
 
166
 
167
  -- This gets data from udp/ip and performs clk domain crossing.
168
  rx_multiclk_fifo : multiclk_fifo
169
    generic map (
170
      re_freq_g    => frequency_g,
171
      we_freq_g    => udp_block_freq_c,
172
      depth_g      => rx_multiclk_fifo_depth_g,
173
      data_width_g => udp_block_data_w_c
174
      )
175
    port map (
176
      clk_re => clk,
177
      clk_we => clk_udp,
178
      rst_n  => rst_n,
179
 
180
      data_in   => rx_data_in,
181
      we_in     => we_to_multiclk_fifo,
182
      full_out  => full_from_multiclk_fifo,
183
      one_p_out => open,
184
      re_in     => re_to_multiclk_fifo,
185
      data_out  => data_from_multiclk_fifo,
186
      empty_out => empty_from_multiclk_fifo,
187
      one_d_out => open
188
      );
189
 
190
 
191
  -- Hibi transmitter reads data from this fifo.
192
  -- Should be exaclt twice as wide and udp/ip data, i.e. 2*16b = 32b.
193
  tx_fifo : fifo
194
    generic map (
195
      data_width_g => hibi_data_width_g,
196
      depth_g      => tx_fifo_depth_g
197
      )
198
    port map (
199
      clk       => clk,
200
      rst_n     => rst_n,
201
      data_in   => data_to_tx_fifo,
202
      we_in     => we_to_tx_fifo,
203
      full_out  => full_from_tx_fifo,
204
      one_p_out => open,
205
 
206
      re_in     => rx_re_in,
207
      data_out  => rx_data_out,
208
      empty_out => rx_empty_out,
209
      one_d_out => open
210
      );
211
 
212
 
213
  -----------------------------------------------------------------------------
214
  -- ** reading data from udp/ip to multiclk fifo **
215
  -- udp_re_multiclk_we_r is used to avoid combinatory loop
216
  -----------------------------------------------------------------------------
217
  rx_re_out           <= udp_re_multiclk_we_r and (not full_from_multiclk_fifo) and (not prevent_read_r);
218
  we_to_multiclk_fifo <= udp_re_multiclk_we_r and rx_data_valid_in and (not prevent_read_r);
219
 
220
  rx_read_to_multiclk : process (clk_udp, rst_n)
221
  begin  -- process rx_read_to_multiclk
222
    if rst_n = '0' then                 -- asynchronous reset (active low)
223
      udp_re_multiclk_we_r <= '0';
224
      rx_data_valid_old_r  <= '0';
225
    elsif clk_udp'event and clk_udp = '1' then  -- rising clock edge
226
 
227
      -- due to the behaviour of the DM9000A eth chip controller block, the data_valid
228
      -- goes down after every read. If we don't lower the re right after it,
229
      -- we are able to read a cycle faster
230
      rx_data_valid_old_r <= rx_data_valid_in;
231
 
232
      if rx_data_valid_in = '1' or rx_data_valid_old_r = '1' then
233
        udp_re_multiclk_we_r <= '1';
234
      else
235
        udp_re_multiclk_we_r <= '0';
236
      end if;
237
    end if;
238
  end process rx_read_to_multiclk;
239
 
240
 
241
 
242
  -----------------------------------------------------------------------------
243
  -- ** reading data from multiclk fifo to tx fifo **
244
  --
245
  -- when the tx is of odd length, empty_from_multiclk_fifo is up when we are
246
  -- supposed to write the last word to tx_fifo
247
  -----------------------------------------------------------------------------
248
  for_tx_fifo_we : process (empty_from_multiclk_fifo, tx_data_cnt_r)
249
  begin  -- process for_tx_fifo_we
250
    if empty_from_multiclk_fifo = '0' or tx_data_cnt_r = 0 then
251
      empty_for_tx_we <= '0';
252
    else
253
      empty_for_tx_we <= '1';
254
    end if;
255
  end process for_tx_fifo_we;
256
 
257
  re_to_multiclk_fifo <= multiclk_re_r and (not (full_from_tx_fifo and read_upper_half_r));
258
  we_to_tx_fifo       <= read_upper_half_r and (not empty_for_tx_we);
259
 
260
  -- Tx fifo is twice as wide as multiclk, so we need to have a buffer
261
  data_to_tx_fifo <= data_from_multiclk_fifo & lower_half_r;
262
 
263
 
264
  -- This process waits for a command from the main process, and then forwards
265
  -- tx_len_r of words from multiclk_fifo to tx_fifo. Or dumps the
266
  -- data i its recevier is not know.
267
  read_multiclk_write_tx_fifo : process (clk, rst_n)
268
  begin  -- process read_multiclk_write_tx_fifo
269
    if rst_n = '0' then                 -- asynchronous reset (active low)
270
 
271
      multiclk_re_r     <= '0';
272
      lower_half_r      <= (others => '0');
273
      read_upper_half_r <= '0';
274
 
275
    elsif clk'event and clk = '1' then  -- rising clock edge
276
 
277
 
278
      case fifo_glue_state_r is
279
 
280
        when idle =>
281
 
282
          -- New tx, start to push data forward
283
          if activate_fifo_glue_r = '1' then
284
            tx_data_cnt_r     <= rx_len_r;
285
            read_upper_half_r <= '0';
286
            fifo_glue_state_r <= working;
287
 
288
          elsif dump_rx_r = '1' then
289
            -- if there is no receiver, just read the tx out of the multiclk
290
            tx_data_cnt_r     <= rx_len_r;
291
            fifo_glue_state_r <= dumping;
292
          end if;
293
 
294
 
295
 
296
        when working =>
297
 
298
          if empty_from_multiclk_fifo = '0' and tx_data_cnt_r /= 0 then
299
            multiclk_re_r <= '1';
300
          end if;
301
 
302
 
303
          if full_from_tx_fifo = '0' and read_upper_half_r = '1'
304
            and (empty_from_multiclk_fifo = '0' or tx_data_cnt_r = 0)
305
          then
306
            -- here we write to the tx fifo
307
            read_upper_half_r <= '0';
308
 
309
            if tx_data_cnt_r < 2 then
310
              -- last word is written now
311
              fifo_glue_state_r <= idle;
312
              multiclk_re_r     <= '0';
313
            else
314
              tx_data_cnt_r <= tx_data_cnt_r-1;
315
            end if;
316
 
317
          elsif multiclk_re_r = '1' and empty_from_multiclk_fifo = '0' and
318
            read_upper_half_r = '0'
319
          then
320
 
321
            -- Write lower half to the tmp buffer
322
            lower_half_r      <= data_from_multiclk_fifo;
323
            read_upper_half_r <= '1';
324
            tx_data_cnt_r     <= tx_data_cnt_r - 1;
325
 
326
            -- prevent reading in case there is another rx waiting right after
327
            -- this one (shouldn't be though...)
328
            if tx_data_cnt_r = 1 then
329
              multiclk_re_r <= '0';
330
            end if;
331
          end if;
332
 
333
 
334
 
335
        when dumping =>
336
          -- No receiver set for this message, so dump it to bit heaven.
337
          if empty_from_multiclk_fifo = '0' then
338
            multiclk_re_r <= '1';
339
          end if;
340
 
341
          if multiclk_re_r = '1' and empty_from_multiclk_fifo = '0' then
342
            if tx_data_cnt_r = 1 then
343
              -- last one, get back to idle
344
              fifo_glue_state_r <= idle;
345
              multiclk_re_r     <= '0';
346
            else
347
              tx_data_cnt_r <= tx_data_cnt_r - 1;
348
            end if;
349
          end if;
350
 
351
        when others => null;
352
      end case;
353
 
354
    end if;
355
  end process read_multiclk_write_tx_fifo;
356
 
357
 
358
  -----------------------------------------------------------------------------
359
  --
360
  -----------------------------------------------------------------------------
361
  main : process (clk, rst_n)
362
  begin  -- process main
363
    if rst_n = '0' then                 -- asynchronous reset (active low)
364
 
365
      activate_fifo_glue_r <= '0';
366
      prevent_read_r       <= '0';
367
      new_rx_old_r         <= '0';
368
      rx_ctrl_state_r      <= wait_rx;
369
      rx_erroneous_r       <= '0';
370
      dump_rx_r            <= '0';
371
      rx_len_r             <= 0;
372
      rx_len_for_ht_r      <= (others => '0');
373
 
374
      ip_out           <= (others => '0');
375
      dest_port_out    <= (others => '0');
376
      source_port_out  <= (others => '0');
377
      send_request_out <= '0';
378
      rx_len_out       <= (others => '0');
379
 
380
 
381
    elsif clk'event and clk = '1' then  -- rising clock edge
382
 
383
      -- **************************************************************************
384
      -- * IMPORTANT NOTE ABOUT SYNCHRONIZATION!                                  *
385
      -- * ... there is no synchronization. Multiclk fifos and thus this whole    *
386
      -- * block requires clk edges to be synchronized even if frequencies differ * 
387
      -- * (must be f1 = k*f2, k E Z+). So having two completely asynchronous     *
388
      -- * clocks will cause metastability. Don't do it.                          *
389
      -- **************************************************************************
390
 
391
      new_rx_old_r         <= new_rx_in;
392
      activate_fifo_glue_r <= '0';
393
      dump_rx_r            <= '0';
394
      send_request_out     <= '0';
395
 
396
      case rx_ctrl_state_r is
397
 
398
        when wait_rx =>
399
 
400
          if new_rx_in = '1' and new_rx_old_r = '0' then
401
            -- Rising edge = new transmission coming from the udp/ip.
402
 
403
            -- Store info. Ctrl-regs will handle these in addr translation.
404
            ip_out          <= source_ip_in;
405
            dest_port_out   <= dest_port_in;
406
            source_port_out <= source_port_in;
407
            rx_erroneous_r  <= rx_erroneous_in;
408
 
409
            -- Convert length in bytes to halfwords (rx_len_r <= rx_len_in/2 + rx_len_in%2)
410
            rx_len_r <= to_integer(unsigned(rx_len_in(tx_len_w_c-1 downto 1)))
411
                        + to_integer(unsigned(rx_len_in(0 downto 0)));
412
 
413
            -- We also have to have the length in bytes for the hibi transmitter
414
            rx_len_for_ht_r <= rx_len_in;
415
 
416
            -- Prevent reading until hibi transmitter ready (or we might
417
            -- accidentally overrun the current info, if this rx was really short
418
            -- and there was another following right after it)
419
            prevent_read_r  <= '1';
420
            rx_ctrl_state_r <= wait_address;
421
 
422
          end if;
423
 
424
 
425
 
426
        when wait_address =>
427
          -- Delay state, it takes a cycle for the ctrl regs to update addr status
428
          rx_ctrl_state_r <= check_address;
429
 
430
 
431
 
432
        when check_address =>
433
          -- The glue process between the multiclk and tx fifos makes sure
434
          -- that only one transfer is being sent to the hibi transmitter.
435
          -- New one can begin, when that process is idle again.
436
 
437
          if fifo_glue_state_r = idle then
438
            if rx_addr_valid_in = '1' and rx_erroneous_r = '0' then
439
              -- There is a receiver for this one, send it forward to the hibi
440
              -- transmitter
441
              if ready_for_tx_in = '1' then
442
                send_request_out     <= '1';
443
                activate_fifo_glue_r <= '1';
444
                prevent_read_r       <= '0';
445
                rx_len_out           <= rx_len_for_ht_r;
446
                rx_ctrl_state_r      <= wait_rx;
447
              end if;
448
 
449
            else
450
              -- No receiver or erroneous, so dump the whole transmission
451
              dump_rx_r       <= '1';
452
              prevent_read_r  <= '0';
453
              rx_ctrl_state_r <= wait_rx;
454
            end if;
455
          end if;
456
 
457
        when others => null;
458
      end case;
459
    end if;
460
  end process main;
461
end rtl;

powered by: WebSVN 2.1.0

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