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

Subversion Repositories xenie

[/] [xenie/] [trunk/] [examples/] [Eth_example/] [ip_repo/] [axi_mdio/] [src/] [axi_mdio_master_top.vhd] - Blame information for rev 4

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 4 DFC
-------------------------------------------------------------------------------
2
--
3
-- (C) Copyright 2017 DFC Design, s.r.o., Brno, Czech Republic
4
-- Author: Marek Kvas (m.kvas@dspfpga.com)
5
-------------------------------------------------------------------------------
6
-- This file is part of UDP/IPv4 for 10 G Ethernet core.
7
-- 
8
-- UDP/IPv4 for 10 G Ethernet core is free software: you can 
9
-- redistribute it and/or modify it under the terms of 
10
-- the GNU Lesser General Public License as published by the Free 
11
-- Software Foundation, either version 3 of the License, or
12
-- (at your option) any later version.
13
-- 
14
-- UDP/IPv4 for 10 G Ethernet core is distributed in the hope that 
15
-- it will be useful, but WITHOUT ANY WARRANTY; without even 
16
-- the implied warranty of MERCHANTABILITY or FITNESS FOR A 
17
-- PARTICULAR PURPOSE.  See the GNU Lesser General Public License 
18
-- for more details.
19
-- 
20
-- You should have received a copy of the GNU Lesser General Public 
21
-- License along with UDP/IPv4 for 10 G Ethernet core.  If not, 
22
-- see <http://www.gnu.org/licenses/>.
23
-------------------------------------------------------------------------------
24
--
25
-- This is top-level file of axi_mdio core that is meant to be used to
26
-- control PHYs via clause 45 MDIO protocol. It can be connected to the system
27
-- using AXI-lite bus.
28
--
29
-- It is clause 45 MDIO master.
30
--
31
-- This file replaced original top-level for wishbone access.
32
-- 
33
--
34
--
35
-------------------------------------------------------------------------------
36
 
37
 
38
 
39
 
40
library ieee;
41
use ieee.std_logic_1164.all;
42
use ieee.numeric_std.all;
43
 
44
 
45
entity mdio_master_top is
46
        generic(
47
      g_include_cmd_fifo   : boolean := true;
48
      g_add_synchronizers  : boolean := true;
49
      C_S_AXI_DATA_WIDTH   : integer := 32;
50
      C_S_AXI_ADDR_WIDTH   : integer := 7
51
        );
52
        port (
53
      -- AXI Lite slave interface for control purposes
54
      -- AXI Lite bus Slave interface
55
      S_AXI_ACLK        : in  std_logic;
56
      S_AXI_ARESETN     : in  std_logic;
57
      S_AXI_AWADDR      : in  std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0);
58
      S_AXI_AWPROT      : in  std_logic_vector(2 downto 0);
59
      S_AXI_AWVALID     : in  std_logic;
60
      S_AXI_AWREADY     : out std_logic;
61
      S_AXI_WDATA       : in  std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
62
      S_AXI_WSTRB       : in std_logic_vector((C_S_AXI_DATA_WIDTH/8)-1 downto 0);
63
      S_AXI_WVALID      : in  std_logic;
64
      S_AXI_WREADY      : out std_logic;
65
      S_AXI_BRESP       : out std_logic_vector(1 downto 0);
66
      S_AXI_BVALID      : out std_logic;
67
      S_AXI_BREADY      : in  std_logic;
68
      S_AXI_ARADDR      : in  std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0);
69
      S_AXI_ARPROT      : in  std_logic_vector(2 downto 0);
70
      S_AXI_ARVALID     : in  std_logic;
71
      S_AXI_ARREADY     : out std_logic;
72
      S_AXI_RDATA       : out std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
73
      S_AXI_RRESP       : out std_logic_vector(1 downto 0);
74
      S_AXI_RVALID      : out std_logic;
75
      S_AXI_RREADY      : in  std_logic;
76
 
77
                -- MDIO lines
78
                MDC     : out std_logic; -- MDIO Clock output
79
      MDIO_I  : in  std_logic; -- MDIO Input data
80
      MDIO_O  : out std_logic; -- MDIO Output data
81
      MDIO_OE : out std_logic  -- MDIO Output Enable, active low!!!
82
        );
83
end entity mdio_master_top;
84
 
85
architecture structural of mdio_master_top is
86
 
87
   COMPONENT cmd_fifo IS
88
      PORT (
89
         clk : IN STD_LOGIC;
90
         srst : IN STD_LOGIC;
91
         din : IN STD_LOGIC_VECTOR(29 DOWNTO 0);
92
         wr_en : IN STD_LOGIC;
93
         rd_en : IN STD_LOGIC;
94
         dout : OUT STD_LOGIC_VECTOR(29 DOWNTO 0);
95
         full : OUT STD_LOGIC;
96
         empty : OUT STD_LOGIC;
97
         data_count : OUT STD_LOGIC_VECTOR(4 DOWNTO 0)
98
      );
99
   END COMPONENT;
100
 
101
 
102
 
103
        -- registers
104
        signal divr          : std_logic_vector(7 downto 0);             -- clock prescale register
105
 
106
        signal mdio_run      : std_logic;
107
   signal mdio_busy     : std_logic;
108
 
109
        signal mdio_dout     : std_logic_vector(15 downto 0);      -- transmit register
110
        signal mdio_din      : std_logic_vector(15 downto 0);      -- receive register
111
 
112
   signal mdio_phyaddr  : std_logic_vector(4 downto 0);
113
   signal mdio_regaddr  : std_logic_vector(4 downto 0);
114
   signal mdio_op       : std_logic_vector(1 downto 0);
115
   signal mdio_start    : std_logic_vector(1 downto 0);
116
   signal mdio_preamb_sup  : std_logic;
117
 
118
--------------------------------------------------------------------------------
119
   -- Signals for AXI state machines
120
   type read_fsm_type is (R_RESET, R_IDLE, R_READ, R_PRESENT);
121
   signal read_fsm_cur : read_fsm_type;
122
 
123
   signal axi_arready_i             : std_logic;
124
   signal axi_rvalid_i              : std_logic;
125
   signal axi_rresp_i               : std_logic_vector(S_AXI_RRESP'range);
126
 
127
   type write_fsm_type is (W_RESET, W_IDLE, W_DATA, W_RESP);
128
   signal write_fsm_cur : write_fsm_type;
129
 
130
   signal axi_awready_i             : std_logic;
131
   signal axi_wready_i              : std_logic;
132
   signal axi_bvalid_i              : std_logic;
133
   signal write_data_latched        : std_logic;
134
 
135
   signal write_data                : std_logic_vector(S_AXI_WDATA'range);
136
   signal write_strb                : std_logic_vector(S_AXI_WSTRB'range);
137
   signal write_addr                : std_logic_vector(S_AXI_AWADDR'range);
138
 
139
   signal reg_read_req              : std_logic;
140
   signal reg_read_ack              : std_logic;
141
   signal reg_write_req             : std_logic;
142
   signal axi_bresp_i               : std_logic_vector(S_AXI_BRESP'range);
143
 
144
   signal axi_rdata_i               : std_logic_vector(S_AXI_RDATA'range);
145
   signal read_addr                 : std_logic_vector(S_AXI_ARADDR'range);
146
   signal reg_read_data             : std_logic_vector(S_AXI_RDATA'range);
147
 
148
--------------------------------------------------------------------------------
149
 
150
   signal mdio_i_meta               : std_logic;
151
   signal mdio_i_sync               : std_logic;
152
 
153
   signal rst                       : std_logic;
154
 
155
   -- Command fifo handling signals
156
   signal cmd_fifo_in               : std_logic_vector(29 downto 0);
157
   signal cmd_fifo_wren             : std_logic;
158
   signal cmd_fifo_rden             : std_logic;
159
   signal cmd_fifo_out              : std_logic_vector(29 downto 0);
160
   signal cmd_fifo_full             : std_logic := '0';
161
   signal cmd_fifo_empty            : std_logic := '1';
162
   signal cmd_fifo_dcount           : std_logic_vector(4 downto 0)
163
                                       := (others => '0');
164
 
165
   signal mdio_busy_prolonged       : std_logic;
166
   signal mdio_busy_prolong_cnt     : unsigned(divr'left + 2 downto 0);
167
 
168
begin
169
 
170
   rst <= not S_AXI_ARESETN;
171
 
172
--------------------------------------------------------------------------------
173
-- AXI Lite slave registers
174
--------------------------------------------------------------------------------
175
   -- Read state machine
176
   read_fsm_proc : process (S_AXI_ACLK)
177
   begin
178
      if rising_edge(S_AXI_ACLK) then
179
         if S_AXI_ARESETN = '0' then
180
            axi_arready_i <= '0';
181
            axi_rvalid_i <= '0';
182
            read_fsm_cur <= R_RESET;
183
            reg_read_req <= '0';
184
         else
185
            reg_read_req <= '0';
186
 
187
            case read_fsm_cur is
188
               when R_RESET =>
189
                  read_fsm_cur <= R_IDLE;
190
                  axi_arready_i <= '1';
191
               when R_IDLE =>
192
                  if S_AXI_ARVALID = '1' then
193
                  -- There is a valid address on the bus, so catch it and read
194
                     read_fsm_cur <= R_READ;
195
                     axi_arready_i <= '0';
196
                     read_addr <= S_AXI_ARADDR;
197
                     reg_read_req <= '1';
198
                  end if;
199
               when R_READ =>
200
--                  reg_read_req <= '1';
201
                  axi_rdata_i <= reg_read_data;
202
                  if reg_read_ack = '1' then
203
                    axi_rvalid_i <= '1';
204
                     read_fsm_cur <= R_PRESENT;
205
                     reg_read_req <= '0';
206
                  end if;
207
               when R_PRESENT =>
208
                  if S_AXI_RREADY = '1' then
209
                     -- Master consumed data, wait for another transaction
210
                     axi_arready_i <= '1';
211
                     axi_rvalid_i <= '0';
212
                     read_fsm_cur <= R_IDLE;
213
                  end if;
214
            end case;
215
         end if;
216
      end if;
217
   end process;
218
   axi_rresp_i <= (others => '0'); -- Read is always OK.
219
 
220
 
221
   --Registers
222
   read_data_mux_proc : process (S_AXI_ACLK)
223
   begin
224
      if rising_edge(S_AXI_ACLK) then
225
         reg_read_ack <= '0';
226
         if reg_read_req = '1' then
227
            reg_read_ack <= '1';
228
 
229
            reg_read_data <= (others => '0');
230
            -- We don't need to decode MSB because it is already checked
231
            -- and we don't have to consider lowest two bits
232
            case to_integer(unsigned(read_addr(read_addr'left downto 2))) is
233
               when 0 => reg_read_data(divr'range) <= divr;
234
               when 1 => reg_read_data(0) <= mdio_busy or not cmd_fifo_empty;
235
                         reg_read_data(12 downto 8) <= cmd_fifo_dcount;
236
                         reg_read_data(13) <= cmd_fifo_full;
237
                         reg_read_data(31 downto 24) <= x"11";
238
               when 2 => reg_read_data(mdio_dout'range) <= mdio_dout;
239
               when 3 => reg_read_data(mdio_din'range) <= mdio_din;
240
               when 4 => reg_read_data(15 downto 0) <= "000000" & mdio_start &
241
                                          "000000" & mdio_op;
242
               when 5 => reg_read_data(15 downto 0) <= "000" & mdio_phyaddr &
243
                                          "000" & mdio_regaddr;
244
               when 6 => reg_read_data <= (others => '0');
245
               when others =>
246
                  reg_read_data <= x"deaddead";
247
            end case;
248
         end if;
249
      end if; -- clk
250
   end process;
251
 
252
   -- Write state machine
253
   write_fsm_proc : process (S_AXI_ACLK)
254
   begin
255
      if rising_edge(S_AXI_ACLK) then
256
         if S_AXI_ARESETN = '0' then
257
            axi_awready_i <= '0';
258
            axi_wready_i <= '0';
259
            axi_bvalid_i <= '0';
260
            write_fsm_cur <= W_RESET;
261
            reg_write_req <= '0';
262
         else
263
            reg_write_req <= '0';
264
 
265
            case write_fsm_cur is
266
               when W_RESET =>
267
                  -- Make sure ready is always high in idle
268
                  write_fsm_cur <= W_IDLE;
269
                  axi_awready_i <= '1';
270
                  axi_wready_i <= '1';
271
                  write_data_latched <= '0';
272
               when W_IDLE =>
273
                  -- Handle address - we can actually update it always
274
                  write_addr <= S_AXI_AWADDR;
275
                  if S_AXI_AWVALID = '1' then
276
                     axi_awready_i <= '0';
277
                     if S_AXI_WVALID = '0' and write_data_latched = '0' then
278
                        -- We need to wait for data
279
                        write_fsm_cur <= W_DATA;
280
                     else
281
                        -- Data are already valid, so we can respond immediately
282
                        write_fsm_cur <= W_RESP;
283
                        -- Respond
284
                        axi_bvalid_i <= '1';
285
 
286
                        -- Start real write to registers
287
                        reg_write_req <= '1';
288
                     end if;
289
                  end if;
290
 
291
                  -- Latch data when valid
292
                  if S_AXI_WVALID = '1' then
293
                     write_data_latched <= '1';
294
                     write_data <= S_AXI_WDATA;
295
                     write_strb <= S_AXI_WSTRB;
296
                     axi_awready_i <= '0';
297
                  end if;
298
               when W_DATA =>
299
                  -- Latch data as soon as valid; address is already here
300
                  if S_AXI_WVALID = '1' then
301
                     write_fsm_cur <= W_RESP;
302
                     axi_bvalid_i <= '1';
303
                      -- Start real write to registers
304
                     reg_write_req <= '1';
305
 
306
                     -- Latch data
307
                     write_data <= S_AXI_WDATA;
308
                     write_strb <= S_AXI_WSTRB;
309
                     axi_awready_i <= '0';
310
                  end if;
311
               when W_RESP =>
312
                  if S_AXI_BREADY = '1' then
313
                     axi_bvalid_i <= '0';
314
                     axi_awready_i <= '1';
315
                     axi_awready_i <= '1';
316
 
317
                     write_fsm_cur <= W_IDLE;
318
                  end if;
319
                  -- This can be done always
320
                  write_data_latched <= '0';
321
            end case;
322
         end if;
323
      end if;
324
   end process;
325
 
326
 
327
   -- Writable registers handling
328
   wr_handling_proc : process (S_AXI_ACLK, S_AXI_ARESETN)
329
   begin
330
      if S_AXI_ARESETN = '0' then
331
         divr <= (others => '1');
332
              mdio_dout  <= (others => '0');
333
              mdio_start  <= (others => '0');
334
         mdio_op <= (others => '0');
335
         mdio_phyaddr <= (others => '0');
336
         mdio_regaddr <= (others => '0');
337
         mdio_run <= '0';
338
         mdio_preamb_sup <= '0';
339
      elsif rising_edge(S_AXI_ACLK) then
340
         mdio_run <= '0'; -- must be active one cycle only
341
 
342
         if reg_write_req = '1' then
343
            case to_integer(unsigned(write_addr(write_addr'left downto 2))) is
344
               when 0 => mdio_preamb_sup   <= write_data(8);
345
                         divr              <= write_data(7 downto 0);
346
               when 1 => mdio_run          <= write_data(1);
347
               when 2 => mdio_dout         <= write_data(mdio_dout'range);
348
               when 3 => null;
349
               when 4 => mdio_start        <= write_data(9 downto 8);
350
                         mdio_op           <= write_data(1 downto 0);
351
               when 5 => mdio_phyaddr      <= write_data(12 downto 8);
352
                         mdio_regaddr      <= write_data(4 downto 0);
353
 
354
               when 6 => mdio_run          <= write_data(31);
355
                         mdio_start        <= write_data(29 downto 28);
356
                         mdio_op           <= write_data(27 downto 26);
357
                         mdio_phyaddr      <= write_data(25 downto 21);
358
                         mdio_regaddr      <= write_data(20 downto 16);
359
                         mdio_dout         <= write_data(mdio_dout'range);
360
 
361
               when others =>
362
                  null;
363
            end case;
364
         end if;
365
      end if;
366
   end process;
367
   -- Response is always OK
368
   axi_bresp_i <= (others => '0');
369
 
370
fifo_gen : if g_include_cmd_fifo generate
371
 
372
   cmd_fifo_in <= mdio_start & mdio_op & mdio_phyaddr & mdio_regaddr & mdio_dout;
373
   cmd_fifo_wren <= mdio_run and not cmd_fifo_full;
374
 
375
   cmd_fifo_inst : cmd_fifo
376
   port map (
377
      clk         => S_AXI_ACLK,
378
      srst        => rst,
379
      din         => cmd_fifo_in,
380
      wr_en       => cmd_fifo_wren,
381
      rd_en       => cmd_fifo_rden,
382
      dout        => cmd_fifo_out,
383
      full        => cmd_fifo_full,
384
      empty       => cmd_fifo_empty,
385
      data_count  => cmd_fifo_dcount
386
   );
387
 
388
   cmd_fifo_rden <= not cmd_fifo_empty and not mdio_busy and not mdio_busy_prolonged;
389
 
390
 
391
    mdio_c_inst : entity work.mdio_c
392
    port map (
393
        CLK             => S_AXI_ACLK,
394
        DIV_CLK         => divr,
395
        PREAMB_SUP      => mdio_preamb_sup,
396
 
397
        START_OP        => cmd_fifo_out(29 downto 28),
398
        OPERATION       => cmd_fifo_out(27 downto 26),
399
        PHY_ADDR        => cmd_fifo_out(25 downto 21),
400
        REG_ADDR        => cmd_fifo_out(20 downto 16),
401
        DATA_IN         => cmd_fifo_out(15 downto 0),
402
        DATA_OUT        => mdio_din,
403
 
404
        DATA_RDY        => open,
405
        RUN_OP          => cmd_fifo_rden,
406
        BUSY            => mdio_busy,
407
 
408
 
409
        MDC             => MDC,
410
        MDIO_I          => mdio_i_sync,
411
        MDIO_O          => MDIO_O,
412
        MDIO_OE         => MDIO_OE
413
        );
414
 
415
    -- prolong busy to keep at leas 2 bit intervals between 
416
    -- consecutive operations
417
    prolong_busy_proc : process(S_AXI_ACLK)
418
    begin
419
       if rising_edge(S_AXI_ACLK) then
420
          if mdio_busy = '1' then
421
             mdio_busy_prolonged <= '1';
422
             mdio_busy_prolong_cnt <= unsigned(divr) & "00";
423
          elsif mdio_busy_prolong_cnt > 0 then
424
             mdio_busy_prolong_cnt <= mdio_busy_prolong_cnt - 1;
425
          else
426
             mdio_busy_prolonged <= '0';
427
          end if;
428
       end if;
429
    end process;
430
 
431
 
432
end generate;
433
 
434
no_fifo_gen : if g_include_cmd_fifo = FALSE generate
435
   cmd_fifo_full <= mdio_busy;
436
 
437
   mdio_c_inst : entity work.mdio_c
438
    port map (
439
        CLK             => S_AXI_ACLK,
440
        DIV_CLK         => divr,
441
        PREAMB_SUP      => mdio_preamb_sup,
442
 
443
        START_OP        => mdio_start,
444
        OPERATION       => mdio_op,
445
        PHY_ADDR        => mdio_phyaddr,
446
        REG_ADDR        => mdio_regaddr,
447
        DATA_IN         => mdio_dout,
448
        DATA_OUT        => mdio_din,
449
 
450
        DATA_RDY        => open,
451
        RUN_OP          => mdio_run,
452
        BUSY            => mdio_busy,
453
 
454
 
455
        MDC             => MDC,
456
        MDIO_I          => mdio_i_sync,
457
        MDIO_O          => MDIO_O,
458
        MDIO_OE         => MDIO_OE
459
        );
460
 end generate;
461
 
462
   -- Add synchronizer on input if required
463
   mdio_i_sync_true : if g_add_synchronizers generate
464
      mdio_i_sync_proc : process(S_AXI_ACLK)
465
      begin
466
         if rising_edge(S_AXI_ACLK) then
467
            mdio_i_meta <= MDIO_I;
468
            mdio_i_sync <= mdio_i_meta;
469
         end if;
470
      end process;
471
   end generate;
472
 
473
   -- If input is already synchronized, don't add useles register chain
474
   mdio_i_sync_false : if not g_add_synchronizers generate
475
      mdio_i_sync <= MDIO_I;
476
   end generate;
477
 
478
 
479
 
480
 
481
 
482
    -- Outputs assignments
483
   S_AXI_AWREADY  <= axi_arready_i;
484
   S_AXI_WREADY   <= axi_wready_i;
485
   S_AXI_BRESP    <= axi_bresp_i;
486
   S_AXI_BVALID   <= axi_bvalid_i;
487
   S_AXI_ARREADY  <= axi_arready_i;
488
   S_AXI_RDATA    <= axi_rdata_i;
489
   S_AXI_RRESP    <= axi_rresp_i;
490
   S_AXI_RVALID   <= axi_rvalid_i;
491
 
492
 
493
 
494
end architecture structural;

powered by: WebSVN 2.1.0

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