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

Subversion Repositories fade_ether_protocol

[/] [fade_ether_protocol/] [trunk/] [stable_jumbo_frames_version/] [fpga/] [src/] [eth_sender64.vhd] - Blame information for rev 44

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 15 wzab
-------------------------------------------------------------------------------
2
-- Title      : FPGA Ethernet interface - block sending packets via XGMII Phy
3
-- Project    : 
4
-------------------------------------------------------------------------------
5
-- File       : eth_sender64.vhd
6
-- Author     : Wojciech M. Zabolotny (wzab@ise.pw.edu.pl)
7
-- License    : BSD License
8
-- Company    : 
9
-- Created    : 2012-03-30
10 18 wzab
-- Last update: 2014-10-12
11 15 wzab
-- Platform   : 
12
-- Standard   : VHDL'93
13
-------------------------------------------------------------------------------
14
-- Description: This file implements the state machine, which manages the
15
-- table of packet descriptors, used to resend only not confirmed packets
16
-------------------------------------------------------------------------------
17
-- Copyright (c) 2012 
18
-------------------------------------------------------------------------------
19
-- Revisions  :
20
-- Date        Version  Author  Description
21
-- 2012-03-30  1.0      WZab      Created
22
-------------------------------------------------------------------------------
23
library ieee;
24
use ieee.std_logic_1164.all;
25
use ieee.numeric_std.all;
26
library work;
27
use work.desc_mgr_pkg.all;
28
use work.pkg_newcrc32_d64.all;
29
 
30
entity eth_sender is
31
 
32
  port (
33
    -- Configuration
34
    peer_mac      : in  std_logic_vector(47 downto 0);
35
    my_mac        : in  std_logic_vector(47 downto 0);
36
    my_ether_type : in  std_logic_vector(15 downto 0);
37
    pkt_number    : in  unsigned(31 downto 0);
38
    seq_number    : in  unsigned(15 downto 0);
39
    transm_delay  : in  unsigned(31 downto 0);
40
    -- System interface
41
    clk           : in  std_logic;
42
    rst_n         : in  std_logic;
43
    -- Control interface
44
    ready         : out std_logic;
45 18 wzab
    flushed       : in  std_logic;
46 15 wzab
    start         : in  std_logic;
47
    cmd_start     : in  std_logic;
48
    -- Data memory interface
49
    tx_mem_addr   : out std_logic_vector(LOG2_N_OF_PKTS+LOG2_NWRDS_IN_PKT-1 downto 0);
50
    tx_mem_data   : in  std_logic_vector(63 downto 0);
51
    -- User command response interface
52
    cmd_response  : in  std_logic_vector(12*8-1 downto 0);
53
    -- TX Phy interface
54
    Tx_Clk        : in  std_logic;
55
    TxC           : out std_logic_vector(7 downto 0);
56
    TxD           : out std_logic_vector(63 downto 0)
57
    );
58
 
59
end eth_sender;
60
 
61
 
62
architecture beh1 of eth_sender is
63
 
64
  type T_ETH_SENDER_STATE is (WST_IDLE, WST_SEND_PREAMB_AND_SOF, WST_SEND_CMD_HEADER,
65
                              WST_SEND_CMD_TRAILER,
66
                              WST_SEND_HEADER, WST_SEND_DATA, WST_SEND_CRC_AND_EOF,
67
                              WST_SEND_COMPLETED);
68
 
69
  type T_ETH_SENDER_REGS is record
70
    state    : T_ETH_SENDER_STATE;
71
    ready    : std_logic;
72
    count    : integer;
73
    word     : integer;
74
    mem_addr : unsigned (LOG2_NWRDS_IN_PKT-1 downto 0);
75
    crc32    : std_logic_vector(31 downto 0);
76
  end record;
77
 
78
  constant ETH_SENDER_REGS_INI : T_ETH_SENDER_REGS := (
79
    state    => WST_IDLE,
80
    ready    => '1',
81
    count    => 0,
82
    word     => 0,
83
    mem_addr => (others => '0'),
84
    crc32    => (others => '0')
85
    ) ;
86
 
87
  signal r, r_n : T_ETH_SENDER_REGS := ETH_SENDER_REGS_INI;
88
 
89
  type T_ETH_SENDER_COMB is record
90
    TxD      : std_logic_vector(63 downto 0);
91
    TxC      : std_logic_vector(7 downto 0);
92
    mem_addr : unsigned(LOG2_NWRDS_IN_PKT-1 downto 0);
93
  end record;
94
 
95
  constant ETH_SENDER_COMB_DEFAULT : T_ETH_SENDER_COMB := (
96
    TxD      => x"07_07_07_07_07_07_07_07",
97
    TxC      => (others => '1'),
98
    mem_addr => (others => '0')
99
    );
100
 
101
  signal c : T_ETH_SENDER_COMB := ETH_SENDER_COMB_DEFAULT;
102
 
103
  signal s_header         : std_logic_vector(8*40-1 downto 0) := (others => '0');
104
  constant HEADER_LEN     : integer                           := 5;  -- 5 words, 8 bytes each
105
  signal s_cmd_header     : std_logic_vector(8*32-1 downto 0) := (others => '0');
106
  constant CMD_HEADER_LEN : integer                           := 4;  -- 4 words, 8 bytes each
107
 
108
  signal cmd_only : std_logic := '0';
109
 
110
  -- The function select_8bytes changes order of bytes, ensuring
111
  -- that the MSB is transmitted first...
112
 
113
  function select_8bytes (
114
    constant vec       : std_logic_vector;
115
    constant chunk_num : integer)
116
    return std_logic_vector is
117
    variable byte_ofs  : integer;
118
    variable chunk_ofs : integer;
119
    variable v_bytes   : std_logic_vector(63 downto 0);
120
  begin
121
    chunk_ofs := chunk_num*64;
122
    -- first select byte
123
    for byte_num in 0 to 7 loop
124
      byte_ofs                            := byte_num * 8;
125
      v_bytes(byte_ofs+7 downto byte_ofs) := vec(vec'left-chunk_ofs-byte_ofs downto vec'left-chunk_ofs-byte_ofs-7);
126
    end loop;  -- byte_num
127
    return v_bytes;
128
  end select_8bytes;
129
 
130
 
131
  function rev(a : in std_logic_vector)
132
    return std_logic_vector is
133
    variable result : std_logic_vector(a'range);
134
    alias aa        : std_logic_vector(a'reverse_range) is a;
135
  begin
136
    for i in aa'range loop
137
      result(i) := aa(i);
138
    end loop;
139
    return result;
140
  end;  -- function reverse_any_bus
141
 
142
  signal tx_rst_n, tx_rst_n_0, tx_rst_n_1          : std_logic := '0';
143
  signal update_flag_0, update_flag_1, update_flag : std_logic := '0';
144
 
145
  signal start_0, tx_start, tx_start_1, tx_start_0 : std_logic := '0';
146
  signal tx_ready, ready_0, ready_1                : std_logic := '0';
147
 
148
  type T_STATE1 is (ST1_IDLE, ST1_WAIT_NOT_READY, ST1_WAIT_NOT_START,
149
                    ST1_WAIT_READY);
150
  signal state1 : T_STATE1;
151
 
152
  type T_STATE2 is (ST2_IDLE, ST2_WAIT_NOT_READY, ST2_WAIT_READY);
153
  signal state2 : T_STATE2;
154 18 wzab
 
155
  signal dta_packet_type : std_logic_vector(15 downto 0) := (others => '0');
156
 
157 15 wzab
begin  -- beh1
158
 
159 18 wzab
  dta_packet_type <= x"a5a5" when flushed = '0' else x"a5a6";
160 15 wzab
  -- Headers should contain n*8 bytes
161
  -- Data packet header
162 18 wzab
  s_header        <= peer_mac & my_mac & my_ether_type & x"0100" &
163
              dta_packet_type & std_logic_vector(seq_number(15 downto 0)) &
164 15 wzab
              std_logic_vector(pkt_number) &
165
              std_logic_vector(transm_delay) & cmd_response;
166
  -- Command response packet header - we have unused 16 bits in the response packet...
167
  s_cmd_header <= peer_mac & my_mac & my_ether_type & x"0100" &
168
                  x"a55a" & x"0000" & cmd_response;
169
 
170
  -- Connection of the signals
171
 
172
  -- The memory address is built from the packet number (6 bits) and word
173
  -- number (8 bits)
174
  tx_mem_addr <= std_logic_vector(pkt_number(LOG2_N_OF_PKTS-1 downto 0)) & std_logic_vector(c.mem_addr);
175
 
176
  -- Main state machine used to send the packet
177
  -- W calej maszynie trzeba jeszcze dodac obsluge kolizji!!!
178
  -- Oprocz tego trzeba przeanalizowac poprawnosc przejsc miedzy domenami zegara
179
 
180
 
181
  snd1 : process (Tx_Clk, tx_rst_n)
182
  begin
183
    if tx_rst_n = '0' then              -- asynchronous reset (active low)
184
      r   <= ETH_SENDER_REGS_INI;
185
      TxD <= x"07_07_07_07_07_07_07_07";
186
      TxC <= (others => '1');
187
    elsif Tx_Clk'event and Tx_Clk = '1' then  -- rising clock edge
188
      r   <= r_n;
189
      -- To minimize glitches and propagation delay, let's add pipeline register
190
      TxC <= c.TxC;
191
      TxD <= c.TxD;
192
    end if;
193
  end process snd1;  -- snd1
194
 
195
  snd2 : process (r, s_header, tx_mem_data, tx_start)
196
    variable v_TxD : std_logic_vector(63 downto 0);
197
  begin  -- process snd1
198
    -- default values
199
    c   <= ETH_SENDER_COMB_DEFAULT;
200
    r_n <= r;
201
    case r.state is
202
      when WST_IDLE =>
203
        c.TxD     <= x"07_07_07_07_07_07_07_07";
204
        c.TxC     <= "11111111";
205
        r_n.ready <= '1';
206
        if tx_start = '1' then
207
          r_n.ready <= '0';
208
          r_n.state <= WST_SEND_PREAMB_AND_SOF;
209
          r_n.count <= 7;
210
        end if;
211
      when WST_SEND_PREAMB_AND_SOF =>
212
        -- Collision detection should be added?
213
        c.TxD     <= x"d5_55_55_55_55_55_55_fb";
214
        c.TxC     <= "00000001";
215
        -- Prepare for sending of header
216
        r_n.crc32 <= (others => '1');
217
        if cmd_only = '1' then
218
          r_n.state <= WST_SEND_CMD_HEADER;
219
        else
220
          r_n.state <= WST_SEND_HEADER;
221
        end if;
222
        r_n.count <= 0;
223
      when WST_SEND_CMD_HEADER =>
224
        v_TxD     := select_8bytes(s_cmd_header, r.count);
225
        c.TxD     <= v_TxD;
226
        c.TxC     <= (others => '0');
227
        r_n.crc32 <= newcrc32_d64(v_TxD, r.crc32);
228
        if r.count < CMD_HEADER_LEN-1 then
229
          r_n.count <= r.count + 1;
230
        else
231
          r_n.count    <= 0;
232
          r_n.word     <= 0;
233
          r_n.mem_addr <= (others => '0');
234
          c.mem_addr   <= (others => '0');
235
          r_n.state    <= WST_SEND_CMD_TRAILER;
236
        end if;
237
      when WST_SEND_CMD_TRAILER =>
238
        v_TxD     := (others => '0');
239
        c.TxD     <= v_TxD;
240
        c.TxC     <= (others => '0');
241
        r_n.crc32 <= newcrc32_d64(v_TxD, r.crc32);
242
        if r.count < 8-CMD_HEADER_LEN-1 then
243
          r_n.count <= r.count + 1;
244
        else
245
          r_n.count    <= 0;
246
          r_n.word     <= 0;
247
          r_n.mem_addr <= (others => '0');
248
          c.mem_addr   <= (others => '0');
249
          r_n.state    <= WST_SEND_CRC_AND_EOF;
250
        end if;
251
      when WST_SEND_HEADER =>
252
        v_TxD     := select_8bytes(s_header, r.count);
253
        c.TxD     <= v_TxD;
254
        c.TxC     <= (others => '0');
255
        r_n.crc32 <= newcrc32_d64(v_TxD, r.crc32);
256
        if r.count < HEADER_LEN-1 then
257
          r_n.count <= r.count + 1;
258
        else
259
          r_n.count    <= 0;
260
          r_n.word     <= 0;
261
          r_n.mem_addr <= (others => '0');
262
          c.mem_addr   <= (others => '0');
263
          r_n.state    <= WST_SEND_DATA;
264
        end if;
265
      when WST_SEND_DATA =>
266
        -- send the data byte by byte
267
        v_TxD     := select_8bytes(tx_mem_data, 0);
268
        r_n.crc32 <= newcrc32_d64(v_TxD, r.crc32);
269
        c.TxD     <= v_TxD;
270
        c.TxC     <= (others => '0');
271
        -- Check, if we have sent all the data
272
        if r.mem_addr < NWRDS_IN_PKT-1 then
273
          r_n.mem_addr <= r.mem_addr + 1;
274
          c.mem_addr   <= r.mem_addr + 1;
275
        else
276
          -- We send the CRC
277
          r_n.state <= WST_SEND_CRC_AND_EOF;
278
        end if;
279
      when WST_SEND_CRC_AND_EOF =>
280
        -- The CRC should be send starting from the most significant bit, so
281
        -- we don't need to reorder bytes in any way...
282
        -- we only reverse it and complement it
283
        v_TxD     := x"07_07_07_fd" & not (rev(r.crc32));
284
        c.TxD     <= v_TxD;
285
        c.TxC     <= "11110000";
286
        r_n.count <= 2;  -- generate the IFG - 16 bytes = 2 words
287
        r_n.state <= WST_SEND_COMPLETED;
288
      when WST_SEND_COMPLETED =>
289
        c.TxD <= x"07_07_07_07_07_07_07_07";
290
        c.TxC <= "11111111";
291
        if r.count > 0 then
292
          r_n.count <= r.count - 1;
293
        else
294
          r_n.ready <= '1';
295
          r_n.state <= WST_IDLE;
296
        end if;
297
    end case;
298
  end process snd2;
299
 
300
 
301
  -- Synchronization of the reset signal for the Tx_Clk domain
302
  process (Tx_Clk, rst_n)
303
  begin  -- process
304
    if rst_n = '0' then                 -- asynchronous reset (active low)
305
      tx_rst_n_0 <= '0';
306
      tx_rst_n_1 <= '0';
307
      tx_rst_n   <= '0';
308
    elsif Tx_Clk'event and Tx_Clk = '1' then  -- rising clock edge
309
      tx_rst_n_0 <= rst_n;
310
      tx_rst_n_1 <= tx_rst_n_0;
311
      tx_rst_n   <= tx_rst_n_1;
312
    end if;
313
  end process;
314
 
315
  -- Synchronization of signals passing clock domains
316
  -- Signal start is sent from the Clk domain.
317
  -- When it is asserted, we must immediately deassert signal ready,
318
  -- then generate the synchronized start and after internal ready
319
  -- is asserted, we can output it again...
320
 
321
  -- Ustawienie na 1 takt zegara "clk" sygnalu start powinno zainicjowac wysylanie
322
  -- w tym bloku musimy zadbac o stosowne wydluzenie sygnalu start i jego synchronizacje
323
  -- miedzy domenami zegara...
324
  process (clk, rst_n)
325
  begin  -- process
326
    if rst_n = '0' then                 -- asynchronous reset (active low)
327
      ready    <= '0';
328
      ready_1  <= '0';
329
      ready_0  <= '0';
330
      cmd_only <= '0';
331
      state2   <= ST2_IDLE;
332
    elsif clk'event and clk = '1' then  -- rising clock edge
333
      ready_1 <= tx_ready;
334
      ready_0 <= ready_1;
335
      case state2 is
336
        when ST2_IDLE =>
337
          if start = '1' and ready_0 = '1' then
338
            start_0  <= '1';
339
            ready    <= '0';
340
            cmd_only <= '0';
341
            state2   <= ST2_WAIT_NOT_READY;
342
          elsif cmd_start = '1' and ready_0 = '1' then
343
            start_0  <= '1';
344
            ready    <= '0';
345
            cmd_only <= '1';
346
            state2   <= ST2_WAIT_NOT_READY;
347
          else
348
            ready <= ready_0;           -- Needed to provide correct start!
349
          end if;
350
        when ST2_WAIT_NOT_READY =>
351
          if ready_0 = '0' then
352
            start_0 <= '0';
353
            state2  <= ST2_WAIT_READY;
354
          end if;
355
        when ST2_WAIT_READY =>
356
          if ready_0 = '1' then
357
            ready  <= '1';
358
            state2 <= ST2_IDLE;
359
          end if;
360
        when others => null;
361
      end case;
362
    end if;
363
  end process;
364
 
365
  process (Tx_Clk, tx_rst_n)
366
  begin  -- process
367
    if tx_rst_n = '0' then              -- asynchronous reset (active low)
368
      tx_start   <= '0';
369
      tx_start_0 <= '0';
370
      state1     <= ST1_IDLE;
371
      tx_ready   <= '1';
372
    elsif Tx_Clk'event and Tx_Clk = '1' then  -- rising clock edge
373
      tx_start_0 <= start_0;
374
      tx_start   <= tx_start_0;
375
      case state1 is
376
        when ST1_IDLE =>
377
          if tx_start = '1' then
378
            tx_ready <= '0';            -- this should cause tx_start to go low
379
            state1   <= ST1_WAIT_NOT_READY;
380
          end if;
381
        when ST1_WAIT_NOT_READY =>
382
          if r.ready = '0' then
383
            state1 <= ST1_WAIT_NOT_START;
384
          end if;
385
        when ST1_WAIT_NOT_START =>
386
          if tx_start = '0' then
387
            state1 <= ST1_WAIT_READY;
388
          end if;
389
        when ST1_WAIT_READY =>
390
          if r.ready = '1' then
391
            tx_ready <= '1';
392
            state1   <= ST1_IDLE;
393
          end if;
394
        when others => null;
395
      end case;
396
    end if;
397
  end process;
398
 
399
end beh1;

powered by: WebSVN 2.1.0

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