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/] [atlys/] [eth_sender8.vhd] - Blame information for rev 44

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

Line No. Rev Author Line
1 15 wzab
-------------------------------------------------------------------------------
2
-- Title      : FPGA Ethernet interface - block sending packets via GMII Phy
3
-- Project    : 
4
-------------------------------------------------------------------------------
5
-- File       : eth_sender8.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-19
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.pkg_newcrc32_d8.all;
28
use work.desc_mgr_pkg.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
    Tx_En         : out std_logic;
56
    TxD           : out std_logic_vector(7 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, WST_SEND_SOF,
65
                              WST_SEND_HEADER, WST_SEND_CMD_HEADER, WST_SEND_CMD_TRAILER,
66
                              WST_SEND_DATA, WST_SEND_CRC,
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
    byte     : 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
    byte     => 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(7 downto 0);
91
    Tx_En    : std_logic;
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      => (others => '0'),
97
    Tx_En    => '0',
98
    mem_addr => (others => '0')
99
    );
100
 
101
  signal c : T_ETH_SENDER_COMB := ETH_SENDER_COMB_DEFAULT;
102
 
103 18 wzab
  signal s_header         : std_logic_vector(8*40-1 downto 0) := (others => '0');
104
  constant HEADER_LEN     : integer                           := 40;  -- 40 bytes
105 15 wzab
  signal s_cmd_header     : std_logic_vector(8*32-1 downto 0) := (others => '0');
106
  constant CMD_HEADER_LEN : integer                           := 32;  -- 32 bytes
107
 
108
  signal cmd_only : std_logic := '0';
109
 
110
  function select_byte (
111
    constant vec      : std_logic_vector;
112
    constant byte_num : integer)
113
    return std_logic_vector is
114
    variable v_byte : std_logic_vector(7 downto 0);
115
  begin
116
    -- first select byte
117
    v_byte := vec(vec'left-byte_num*8 downto vec'left-byte_num*8-7);
118
    return v_byte;
119
  end select_byte;
120
 
121
  function rev(a : in std_logic_vector)
122
    return std_logic_vector is
123
    variable result : std_logic_vector(a'range);
124
    alias aa        : std_logic_vector(a'reverse_range) is a;
125
  begin
126
    for i in aa'range loop
127
      result(i) := aa(i);
128
    end loop;
129
    return result;
130
  end;  -- function reverse_any_bus
131
 
132
  signal tx_rst_n, tx_rst_n_0, tx_rst_n_1          : std_logic := '0';
133
  signal update_flag_0, update_flag_1, update_flag : std_logic := '0';
134
 
135
  signal start_0, tx_start, tx_start_1, tx_start_0 : std_logic := '0';
136
  signal tx_ready, ready_0, ready_1                : std_logic := '0';
137
 
138
  type T_STATE1 is (ST1_IDLE, ST1_WAIT_NOT_READY, ST1_WAIT_NOT_START,
139
                    ST1_WAIT_READY);
140
  signal state1 : T_STATE1;
141
 
142
  type T_STATE2 is (ST2_IDLE, ST2_WAIT_NOT_READY, ST2_WAIT_READY);
143 18 wzab
  signal state2          : T_STATE2;
144
  signal dta_packet_type : std_logic_vector(15 downto 0) := (others => '0');
145
 
146 15 wzab
begin  -- beh1
147 18 wzab
  dta_packet_type <= x"a5a5" when flushed = '0' else x"a5a6";
148 15 wzab
  -- Packet header
149 18 wzab
  s_header        <= peer_mac & my_mac & my_ether_type & x"0100" &
150
              dta_packet_type & std_logic_vector(seq_number(15 downto 0)) &
151
              std_logic_vector(pkt_number) & std_logic_vector(transm_delay) & cmd_response;
152 15 wzab
  -- Command response packet header - we have unused 16 bits in the response packet...
153
  s_cmd_header <= peer_mac & my_mac & my_ether_type & x"0100" &
154
                  x"a55a" & x"0000" & cmd_response;
155
 
156
  -- Connection of the signals
157
 
158
  -- The memory address is built from the packet number (6 bits) and word
159
  -- number (8 bits)
160
  tx_mem_addr <= std_logic_vector(pkt_number(LOG2_N_OF_PKTS-1 downto 0)) & std_logic_vector(c.mem_addr);
161
 
162
  -- Main state machine used to send the packet
163
  -- W calej maszynie trzeba jeszcze dodac obsluge kolizji!!!
164
  -- Oprocz tego trzeba przeanalizowac poprawnosc przejsc miedzy domenami zegara
165
 
166
 
167
  snd1 : process (Tx_Clk, tx_rst_n)
168
  begin
169
    if tx_rst_n = '0' then              -- asynchronous reset (active low)
170
      r     <= ETH_SENDER_REGS_INI;
171
      TxD   <= (others => '0');
172
      Tx_En <= '0';
173
    elsif Tx_Clk'event and Tx_Clk = '1' then  -- rising clock edge
174
      r     <= r_n;
175
      -- To minimize glitches and propagation delay, let's add pipeline register
176
      Tx_En <= c.Tx_En;
177
      TxD   <= c.TxD;
178
    end if;
179
  end process snd1;  -- snd1
180
 
181
  snd2 : process (r, s_header, tx_mem_data, tx_start)
182
    variable v_TxD : std_logic_vector(7 downto 0);
183
  begin  -- process snd1
184
    -- default values
185
    c   <= ETH_SENDER_COMB_DEFAULT;
186
    r_n <= r;
187
    case r.state is
188
      when WST_IDLE =>
189
        r_n.ready <= '1';
190
        if tx_start = '1' then
191
          r_n.ready <= '0';
192
          r_n.state <= WST_SEND_PREAMB;
193
          r_n.count <= 7;
194
        end if;
195
      when WST_SEND_PREAMB =>
196
        -- Trzeba dodac wykrywanie kolizji!
197
        c.TxD     <= x"55";
198
        c.Tx_En   <= '1';
199
        r_n.count <= r.count - 1;
200
        if r.count = 1 then
201
          r_n.state <= WST_SEND_SOF;
202
        end if;
203
      when WST_SEND_SOF =>
204
        c.TxD     <= x"D5";
205
        c.Tx_En   <= '1';
206
        -- Prepare for sending of header
207
        r_n.crc32 <= (others => '1');
208
        if cmd_only = '1' then
209
          r_n.state <= WST_SEND_CMD_HEADER;
210
        else
211 18 wzab
          r_n.state <= WST_SEND_HEADER;
212 15 wzab
        end if;
213
        r_n.count <= 0;
214
      when WST_SEND_CMD_HEADER =>
215
        v_TxD     := select_byte(s_cmd_header, r.count);
216
        c.TxD     <= v_TxD;
217
        c.Tx_En   <= '1';
218
        r_n.crc32 <= newcrc32_d8(v_TxD, r.crc32);
219
        if r.count < CMD_HEADER_LEN-1 then
220
          r_n.count <= r.count + 1;
221
        else
222
          r_n.count    <= 0;
223
          r_n.byte     <= 0;
224
          r_n.mem_addr <= (others => '0');
225
          c.mem_addr   <= (others => '0');
226
          r_n.state    <= WST_SEND_CMD_TRAILER;
227
        end if;
228
      when WST_SEND_CMD_TRAILER =>
229
        v_TxD     := (others => '0');
230
        c.TxD     <= v_TxD;
231
        c.Tx_En   <= '1';
232
        r_n.crc32 <= newcrc32_d8(v_TxD, r.crc32);
233
        if r.count < 64-CMD_HEADER_LEN-1 then
234
          r_n.count <= r.count + 1;
235
        else
236
          r_n.count    <= 0;
237
          r_n.byte     <= 0;
238
          r_n.mem_addr <= (others => '0');
239
          c.mem_addr   <= (others => '0');
240
          r_n.state    <= WST_SEND_CRC;
241
        end if;
242 18 wzab
      when WST_SEND_HEADER =>
243 15 wzab
        v_TxD     := select_byte(s_header, r.count);
244
        c.TxD     <= v_TxD;
245
        c.Tx_En   <= '1';
246
        r_n.crc32 <= newcrc32_d8(v_TxD, r.crc32);
247
        if r.count < HEADER_LEN-1 then
248
          r_n.count <= r.count + 1;
249
        else
250
          r_n.count    <= 0;
251
          r_n.byte     <= 0;
252
          r_n.mem_addr <= (others => '0');
253
          c.mem_addr   <= (others => '0');
254
          r_n.state    <= WST_SEND_DATA;
255
        end if;
256
      when WST_SEND_DATA =>
257
        -- send the data byte by byte
258
        v_TxD     := select_byte(tx_mem_data, r.byte);
259
        c.TxD     <= v_TxD;
260
        c.Tx_En   <= '1';
261
        r_n.crc32 <= newcrc32_d8(v_TxD, r.crc32);
262
        if r.byte < 7 then
263
          r_n.byte   <= r.byte + 1;
264
          c.mem_addr <= r.mem_addr;
265
        else
266
          r_n.byte <= 0;
267
          -- Check, if we have sent all the data
268
          -- We send 8192 bytes, which takes 1024 64-bit words
269
          if r.mem_addr < 1023 then
270
            r_n.mem_addr <= r.mem_addr + 1;
271
            c.mem_addr   <= r.mem_addr + 1;
272
          else
273
            -- We send the CRC
274
            r_n.state <= WST_SEND_CRC;
275
          end if;
276
        end if;
277
      when WST_SEND_CRC =>
278 26 wzab
        v_TxD   := r.crc32(31-r.byte*8 downto 24-r.byte*8);
279 15 wzab
        c.TxD   <= not rev(v_TxD);
280
        c.Tx_En <= '1';
281
        if r.byte < 3 then
282
          r_n.byte <= r.byte + 1;
283
        else
284
          r_n.count <= 12;              -- generate the IFG - 12 bytes = 96
285
                                        -- bits
286
          r_n.state <= WST_SEND_COMPLETED;
287
        end if;
288
      when WST_SEND_COMPLETED =>
289
        if r.count > 0 then
290
          r_n.count <= r.count - 1;
291
        else
292
          r_n.ready <= '1';
293
          r_n.state <= WST_IDLE;
294
        end if;
295
    end case;
296
  end process snd2;
297
 
298
 
299
  -- Synchronization of the reset signal for the Tx_Clk domain
300
  process (Tx_Clk, rst_n)
301
  begin  -- process
302
    if rst_n = '0' then                 -- asynchronous reset (active low)
303
      tx_rst_n_0 <= '0';
304
      tx_rst_n_1 <= '0';
305
      tx_rst_n   <= '0';
306
    elsif Tx_Clk'event and Tx_Clk = '1' then  -- rising clock edge
307
      tx_rst_n_0 <= rst_n;
308
      tx_rst_n_1 <= tx_rst_n_0;
309
      tx_rst_n   <= tx_rst_n_1;
310
    end if;
311
  end process;
312
 
313
  -- Synchronization of signals passing clock domains
314
  -- Signal start is sent from the Clk domain.
315
  -- When it is asserted, we must immediately deassert signal ready,
316
  -- then generate the synchronized start and after internal ready
317
  -- is asserted, we can output it again...
318
 
319
  -- Ustawienie na 1 takt zegara "clk" sygnalu start powinno zainicjowac wysylanie
320
  -- w tym bloku musimy zadbac o stosowne wydluzenie sygnalu start i jego synchronizacje
321
  -- miedzy domenami zegara...
322
  process (clk, rst_n)
323
  begin  -- process
324
    if rst_n = '0' then                 -- asynchronous reset (active low)
325
      ready   <= '0';
326
      ready_1 <= '0';
327
      ready_0 <= '0';
328
      state2  <= ST2_IDLE;
329
    elsif clk'event and clk = '1' then  -- rising clock edge
330
      ready_1 <= tx_ready;
331
      ready_0 <= ready_1;
332
      case state2 is
333
        when ST2_IDLE =>
334
          if start = '1' and ready_0 = '1' then
335
            cmd_only <= '0';
336 18 wzab
            start_0  <= '1';
337
            ready    <= '0';
338
            state2   <= ST2_WAIT_NOT_READY;
339 15 wzab
          elsif cmd_start = '1' and ready_0 = '1' then
340
            cmd_only <= '1';
341 18 wzab
            start_0  <= '1';
342
            ready    <= '0';
343
            state2   <= ST2_WAIT_NOT_READY;
344 15 wzab
          else
345
            ready <= ready_0;           -- Needed to provide correct start!
346
          end if;
347
        when ST2_WAIT_NOT_READY =>
348
          if ready_0 = '0' then
349
            start_0 <= '0';
350
            state2  <= ST2_WAIT_READY;
351
          end if;
352
        when ST2_WAIT_READY =>
353
          if ready_0 = '1' then
354
            ready  <= '1';
355
            state2 <= ST2_IDLE;
356
          end if;
357
        when others => null;
358
      end case;
359
    end if;
360
  end process;
361
 
362
  process (Tx_Clk, tx_rst_n)
363
  begin  -- process
364
    if tx_rst_n = '0' then              -- asynchronous reset (active low)
365
      tx_start   <= '0';
366
      tx_start_0 <= '0';
367
      state1     <= ST1_IDLE;
368
      tx_ready   <= '1';
369
    elsif Tx_Clk'event and Tx_Clk = '1' then  -- rising clock edge
370
      tx_start_0 <= start_0;
371
      tx_start   <= tx_start_0;
372
      case state1 is
373
        when ST1_IDLE =>
374
          if tx_start = '1' then
375
            tx_ready <= '0';            -- this should cause tx_start to go low
376
            state1   <= ST1_WAIT_NOT_READY;
377
          end if;
378
        when ST1_WAIT_NOT_READY =>
379
          if r.ready = '0' then
380
            state1 <= ST1_WAIT_NOT_START;
381
          end if;
382
        when ST1_WAIT_NOT_START =>
383
          if tx_start = '0' then
384
            state1 <= ST1_WAIT_READY;
385
          end if;
386
        when ST1_WAIT_READY =>
387
          if r.ready = '1' then
388
            tx_ready <= '1';
389
            state1   <= ST1_IDLE;
390
          end if;
391
        when others => null;
392
      end case;
393
    end if;
394
  end process;
395
 
396
end beh1;

powered by: WebSVN 2.1.0

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