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/] [eth_dm9000a_ctrl/] [1.0/] [vhd/] [DM9kA_send_module.vhd] - Blame information for rev 183

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

Line No. Rev Author Line
1 145 lanttu
-------------------------------------------------------------------------------
2
-- Title      : DM9kA controller, sender module
3
-- Project    : 
4
-------------------------------------------------------------------------------
5
-- File       : DM9kA_send_module.vhd
6
-- Author     : Jussi Nieminen  <niemin95@galapagosinkeiju.cs.tut.fi>
7
-- Last update: 2012-04-04
8
-------------------------------------------------------------------------------
9
-- Description: Handles sending procedures application -> eth
10
-- Includes a state machine where two states (init and done) include their own
11
-- sub-state machines.
12
-------------------------------------------------------------------------------
13
-- Revisions  :
14
-- Date        Version  Author  Description
15
-- 2009/08/25  1.0      niemin95        Created
16
-------------------------------------------------------------------------------
17
 
18
library ieee;
19
use ieee.std_logic_1164.all;
20
use ieee.numeric_std.all;
21
use work.DM9kA_ctrl_pkg.all;
22
 
23
 
24
entity DM9kA_send_module is
25
 
26
  port (
27
    clk                     : in  std_logic;
28
    rst_n                   : in  std_logic;
29
    -- from interrupt handler
30
    tx_completed_in         : in  std_logic;
31
    -- to and from comm module
32
    comm_req_out            : out std_logic;
33
    comm_grant_in           : in  std_logic;
34
    reg_addr_out            : out std_logic_vector(7 downto 0);
35
    config_data_out         : out std_logic_vector(7 downto 0);
36
    read_not_write_out      : out std_logic;
37
    config_valid_out        : out std_logic;
38
    data_from_comm_in       : in  std_logic_vector(data_width_c-1 downto 0);
39
    data_from_comm_valid_in : in  std_logic;
40
    comm_busy_in            : in  std_logic;
41
    -- to comm module
42
    tx_data_out             : out std_logic_vector(data_width_c-1 downto 0);
43
    tx_data_valid_out       : out std_logic;
44
    tx_re_in                : in  std_logic;
45
    -- from upper level
46
    tx_data_in              : in  std_logic_vector(data_width_c-1 downto 0);
47
    tx_data_valid_in        : in  std_logic;
48
    tx_re_out               : out std_logic;
49
    tx_MAC_addr_in          : in  std_logic_vector(47 downto 0);
50
    new_tx_in               : in  std_logic;
51
    tx_len_in               : in  std_logic_vector(tx_len_w_c-1 downto 0);
52
    tx_frame_type_in        : in  std_logic_vector(15 downto 0)
53
    );
54
 
55
end DM9kA_send_module;
56
 
57
 
58
architecture rtl of DM9kA_send_module is
59
 
60
  -- There are 3 state machines.
61
  -- not much to initialize, but our own MAC we must get
62
  type   init_state_type is (get_MAC, done);
63
  signal init_state_r : init_state_type;
64
 
65
  -- This FSM is used during init to read mac addr
66
  type   conf_state_type is (write_conf, read_reply, wait_busy);
67
  signal conf_state_r : conf_state_type;
68
 
69
  -- counter used when getting the MAC address
70
  signal addr_cnt_r : integer range 0 to MAC_len_c-1;
71
 
72
  -- vhdl doesn't understand signals indexing std_logic_vectors, so we have to
73
  -- do this:
74
  type MAC_addr_type is array (0 to MAC_len_c-1) of std_logic_vector(7 downto 0);
75
 
76
  signal own_MAC_r  : MAC_addr_type;
77
  signal trgt_MAC_r : MAC_addr_type;
78
 
79
  -- This FSM is used in normal operation
80
  type tx_state_type is (wait_tx, conf_len_hi, conf_len_lo, conf_tx_reg,
81
                         write_trgt_MAC, write_own_MAC, write_frame_type,
82
                         count_data, send_cmd);
83
  signal tx_state_r : tx_state_type;
84
 
85
 
86
 
87
  signal tx_len_r      : std_logic_vector(tx_len_w_c-1 downto 0);
88
  signal tx_len_int    : integer range 0 to 2**tx_len_w_c-1;
89
  signal tx_data_cnt_r : integer range 0 to 2**tx_len_w_c-1;
90
 
91
  signal tx_data_r       : std_logic_vector(data_width_c-1 downto 0);
92
  signal tx_data_valid_r : std_logic;
93
 
94
  signal comm_req_r       : std_logic;
95
  signal start_counting_r : std_logic;
96
 
97
  -- there can be maximum of 2 transfers at a time
98
  signal tx_count_r : integer range 0 to 2;
99
 
100
 
101
-------------------------------------------------------------------------------
102
begin  -- rtl
103
-------------------------------------------------------------------------------
104
 
105
  --
106
  -- Combinatorial process
107
  -- switch between inner registers and data input
108
  -- 
109
  tx_data_mux : process (tx_data_in, tx_data_valid_in, tx_state_r,
110
                        tx_data_r, tx_data_valid_r, tx_re_in)
111
  begin  -- process tx_data_mux
112
 
113
    if tx_state_r /= count_data then
114
      -- writing ethernet frame headers
115
      tx_data_out       <= tx_data_r;
116
      tx_data_valid_out <= tx_data_valid_r;
117
      -- no re to upper level
118
      tx_re_out         <= '0';
119
 
120
    else
121
      -- writing payload
122
      tx_data_out       <= tx_data_in;
123
      tx_data_valid_out <= tx_data_valid_in;
124
      tx_re_out         <= tx_re_in;
125
 
126
    end if;
127
  end process tx_data_mux;
128
 
129
  comm_req_out <= comm_req_r;
130
  tx_len_int   <= to_integer(unsigned(tx_len_r));
131
 
132
 
133
  --
134
  -- Sequential process for state machine
135
  --
136
  main : process (clk, rst_n)
137
 
138
    -- helping with odd length transfers
139
    variable odd_len_compensation_v : integer range 0 to 1;
140
 
141
  begin  -- process main
142
    if rst_n = '0' then                 -- asynchronous reset (active low)
143
 
144
      init_state_r <= get_MAC;
145
      tx_state_r   <= wait_tx;
146
      conf_state_r <= write_conf;
147
 
148
      own_MAC_r  <= (others => (others => '0'));
149
      trgt_MAC_r <= (others => (others => '0'));
150
      addr_cnt_r <= 0;
151
 
152
      reg_addr_out       <= (others => '0');
153
      config_data_out    <= (others => '0');
154
      config_valid_out   <= '0';
155
      read_not_write_out <= '0';
156
 
157
      comm_req_r       <= '0';
158
      tx_data_r        <= (others => '0');
159
      tx_data_valid_r  <= '0';
160
      tx_len_r         <= (others => '0');
161
      start_counting_r <= '0';
162
      tx_count_r       <= 0;
163
 
164
    elsif clk'event and clk = '1' then  -- rising clock edge
165
 
166
      -- decrease counter when a tx is completed
167
      if tx_completed_in = '1' then
168
        tx_count_r <= tx_count_r - 1;
169
      end if;
170
 
171
 
172
 
173
      case init_state_r is
174
        -----------------------------------------------------------------------
175
        -- Getting our own MAC address, needs another state machine
176
        when get_MAC =>
177
 
178
          comm_req_r <= '1';
179
 
180
          if comm_grant_in = '1' then
181
            -- sender has comm modules attention
182
 
183
            case conf_state_r is
184
              when write_conf =>
185
 
186
                -- MAC address is in registers x'10 -> x'15
187
                reg_addr_out       <= std_logic_vector(unsigned(MAC6_c) - to_unsigned(addr_cnt_r, 8));
188
                read_not_write_out <= '1';
189
                config_valid_out   <= '1';
190
 
191
                -- when busy comes up, comm module has started working
192
                if comm_busy_in = '1' then
193
                  conf_state_r <= read_reply;
194
                end if;
195
 
196
              when read_reply =>
197
 
198
                if data_from_comm_valid_in = '1' then
199
                  own_MAC_r(addr_cnt_r) <= data_from_comm_in(7 downto 0);
200
                  conf_state_r          <= wait_busy;
201
                end if;
202
 
203
              when wait_busy =>
204
 
205
                if comm_busy_in = '0' then
206
 
207
                  if addr_cnt_r = MAC_len_c-1 then
208
                    init_state_r     <= done;
209
                    addr_cnt_r       <= 0;
210
                    comm_req_r       <= '0';
211
                    config_valid_out <= '0';
212
                  else
213
                    addr_cnt_r <= addr_cnt_r + 1;
214
                  end if;
215
                  conf_state_r <= write_conf;
216
 
217
                end if;
218
              when others => null;
219
            end case;
220
          end if;
221
          -----------------------------------------------------------------------
222
          -- MAC address received, moving on
223
 
224
        when done =>
225
          -- init done, meaning normal operation
226
 
227
          -- new_tx_in, tx_len_in and tx_MAC_addr_in must remain stable until
228
          -- the first data is read from the upper level.
229
 
230
          -- tx state machine
231
          case tx_state_r is
232
            when wait_tx =>
233
 
234
              -- new transfer waiting, and less than 2 on the way
235
              if new_tx_in = '1' and tx_count_r /= 2 then
236
                -- add here checking of number of on-going txs
237
 
238
                comm_req_r <= '1';
239
                tx_len_r   <= std_logic_vector(unsigned(tx_len_in) + to_unsigned(eth_header_len_c, tx_len_w_c));
240
 
241
                for n in 0 to MAC_len_c-1 loop
242
                  trgt_MAC_r(n) <= tx_MAC_addr_in((n+1)*8-1 downto n*8);
243
                end loop;  -- n
244
 
245
                if comm_grant_in = '1' and comm_req_r = '1' then
246
                  -- increase number of txs
247
                  tx_count_r <= tx_count_r + 1;
248
                  tx_state_r <= conf_len_hi;
249
                end if;
250
              end if;
251
 
252
            when conf_len_hi =>
253
 
254
              -- write high part of the tx len
255
              case conf_state_r is
256
                when write_conf =>
257
 
258
                  reg_addr_out                             <= TXPLH_c;
259
                  -- upper bits remain zero while lower ones get the values of
260
                  -- higher tx len bits
261
                  config_data_out                          <= (others => '0');
262
                  config_data_out(tx_len_w_c-8-1 downto 0) <= tx_len_r(tx_len_w_c-1 downto 8);
263
                  read_not_write_out                       <= '0';
264
                  config_valid_out                         <= '1';
265
 
266
                  if comm_busy_in = '1' then
267
                    conf_state_r <= wait_busy;
268
                  end if;
269
 
270
                when wait_busy =>
271
 
272
                  if comm_busy_in = '0' then
273
                    config_valid_out <= '0';
274
                    conf_state_r     <= write_conf;
275
                    tx_state_r       <= conf_len_lo;
276
                  end if;
277
 
278
                when others => null;
279
              end case;
280
 
281
            when conf_len_lo =>
282
 
283
              -- write lower part of the tx len
284
              case conf_state_r is
285
                when write_conf =>
286
 
287
                  reg_addr_out       <= TXPLL_c;
288
                  config_data_out    <= tx_len_r(7 downto 0);
289
                  read_not_write_out <= '0';
290
                  config_valid_out   <= '1';
291
 
292
                  if comm_busy_in = '1' then
293
                    conf_state_r <= wait_busy;
294
                  end if;
295
 
296
                when wait_busy =>
297
 
298
                  if comm_busy_in = '0' then
299
                    config_valid_out <= '0';
300
                    conf_state_r     <= write_conf;
301
                    tx_state_r       <= conf_tx_reg;
302
                  end if;
303
 
304
                when others => null;
305
              end case;
306
 
307
 
308
            when conf_tx_reg =>
309
 
310
              -- when the address of tx register is written, comm module
311
              -- automagically switches to tx mode and starts receiving tx data
312
              -- until config_valid_out signal is lowered.
313
 
314
              reg_addr_out       <= tx_data_reg_c;
315
              read_not_write_out <= '0';
316
              config_valid_out   <= '1';
317
 
318
              -- when comm busy, move to send phase
319
              if comm_busy_in = '1' then
320
                tx_state_r <= write_trgt_MAC;
321
                addr_cnt_r <= 0;
322
              end if;
323
 
324
 
325
            when write_trgt_MAC =>
326
 
327
              -- write two bytes of address at once (MSB first)
328
              tx_data_r <= trgt_MAC_r(MAC_len_c - 2*addr_cnt_r - 2)
329
                           & trgt_MAC_r(MAC_len_c - 2*addr_cnt_r - 1);
330
              tx_data_valid_r <= '1';
331
 
332
              -- when comm reads, increase counter or move on
333
              if tx_re_in = '1' then
334
                if addr_cnt_r = MAC_len_c/2 - 1 then
335
                  tx_data_valid_r <= '0';
336
                  addr_cnt_r      <= 0;
337
                  tx_state_r      <= write_own_MAC;
338
                else
339
                  addr_cnt_r <= addr_cnt_r + 1;
340
                end if;
341
              end if;
342
 
343
 
344
            when write_own_MAC =>
345
 
346
              tx_data_r <= own_MAC_r(MAC_len_c - 2*addr_cnt_r - 2)
347
                           & own_MAC_r(MAC_len_c - 2*addr_cnt_r - 1);
348
              tx_data_valid_r <= '1';
349
 
350
              -- when comm reads, increase counter or move on
351
              if tx_re_in = '1' then
352
                if addr_cnt_r = MAC_len_c/2 - 1 then
353
                  tx_data_valid_r <= '0';
354
                  addr_cnt_r      <= 0;
355
                  tx_state_r      <= write_frame_type;
356
                else
357
                  addr_cnt_r <= addr_cnt_r + 1;
358
                end if;
359
              end if;
360
 
361
 
362
            when write_frame_type =>
363
 
364
              tx_data_r       <= tx_frame_type_in(7 downto 0) & tx_frame_type_in(15 downto 8);
365
              tx_data_valid_r <= '1';
366
 
367
              if tx_re_in = '1' then
368
                -- the tx_data mux now switches the output, so we can clear
369
                -- these registers
370
                tx_data_r        <= (others => '0');
371
                tx_data_valid_r  <= '0';
372
                tx_data_cnt_r    <= 0;
373
                start_counting_r <= '1';
374
              end if;
375
 
376
              -- delay, so that changing input of tx_re_out doesn't cause a glitch
377
              if start_counting_r = '1' then
378
                tx_data_r        <= (others => '0');
379
                tx_data_valid_r  <= '0';
380
                tx_data_cnt_r    <= 0;
381
                start_counting_r <= '0';
382
                tx_state_r       <= count_data;
383
              end if;
384
 
385
 
386
            when count_data =>
387
              -- data comes straight from the upper level, just count how much
388
              -- has been sent and stop the transmission in time
389
 
390
              if tx_re_in = '1' then
391
 
392
                -- tx len in bytes but writing words, that's why the division
393
                -- by two
394
                odd_len_compensation_v := to_integer(unsigned(tx_len_r(0 downto 0)));
395
                if tx_data_cnt_r = (tx_len_int - eth_header_len_c) / 2 - 1 + odd_len_compensation_v then
396
                  -- All sent. Notify the comm module by lowering the config_valid_out
397
                  config_valid_out <= '0';
398
                  tx_data_cnt_r    <= 0;
399
 
400
                  -- request send if constant says so (if DM9kA is configured
401
                  -- to start sending in advance, there is no need to raise the
402
                  -- tx request bit)
403
                  if send_cmd_en_c = 1 then
404
                    tx_state_r <= send_cmd;
405
                  else
406
                    tx_state_r <= wait_tx;
407
                    comm_req_r <= '0';
408
                  end if;
409
 
410
                else
411
                  tx_data_cnt_r <= tx_data_cnt_r + 1;
412
                end if;
413
              end if;
414
 
415
 
416
            when send_cmd =>
417
 
418
              -- feed in send cmd
419
              case conf_state_r is
420
                when write_conf =>
421
 
422
                  reg_addr_out       <= TCR_c;
423
                  -- start tx
424
                  config_data_out    <= x"01";
425
                  read_not_write_out <= '0';
426
                  config_valid_out   <= '1';
427
 
428
                  if comm_busy_in = '1' then
429
                    conf_state_r <= wait_busy;
430
                  end if;
431
 
432
                when wait_busy =>
433
 
434
                  if comm_busy_in = '0' then
435
                    config_valid_out <= '0';
436
                    conf_state_r     <= write_conf;
437
                    tx_state_r       <= wait_tx;
438
                    comm_req_r       <= '0';
439
                  end if;
440
 
441
                when others => null;
442
              end case;
443
 
444
 
445
            when others => null;
446
          end case;  -- tx_state_r
447
        when others => null;
448
      end case;  -- init_state_r
449
    end if;
450
  end process main;
451
 
452
 
453
end rtl;

powered by: WebSVN 2.1.0

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