Jump to content

escou64

Members
  • Posts

    3
  • Joined

  • Last visited

Posts posted by escou64

  1. Hi,

    I am trying to design an ethernet controller for my Genesys 2. From specifications (RGMII, Realtek RTL8211E-VL PHY) or other projects (special thanks to @zygot and his Ethernet PHY Test Tool project), I have successfully implemented the Tx transmitter part: I can now see the different packets with WireShark. However, I am now facing a problem in the Rx receiver part. After analyzing the signals, I've noticed that the issue seems to come from the signals that are received from the PHY. Below is a screenshot of a received packet observed from an ILA: the sampling clock is at 500MHz (so the waveform accuracy must be put into perspective).

    ILA_RGMII_Rx.thumb.png.f218e3ab1e1b5ab3f5adeae59897d4de.png

    The original packet starts with: ff ff ff ff ff ff a4 b1 c1 31 d8 05 08 00 45 00 ...

    But as early as the preamble/SFD, it seems that a shift exists with the first 4 bits received on a falling edge. So my frame becomes 5X  55 55 55 55 55 55 fd ff ... instead of the expected 55 55 55 55 55 55 55 5d ff... And it stays like that until the end of the frame, and for all the received frames.

    Here are the corresponding Verilog and constraints parts inspired by the previously mentioned sources:

     

    // Verilog top file
    input logic         i_eth_mii_rx_clk;		// Input Rx Clock
    input logic         i_eth_mii_rx_ctl;		// Input Rx CTL
    input logic [3:0]   i_eth_mii_rx_data;		// Input Rx Data
    
    logic         		w_eth_mii_rx_clk;		// Internal Rx Clock
    logic         		w_eth_mii_rx_rst;		// Internal Rx Reset
    logic [1:0]   		w_eth_mii_rx_ctl;		// Internal Rx CTL
    logic    		    w_eth_mii_rx_en;		// Internal Rx Enable
    logic    		    w_eth_mii_rx_err;		// Internal Rx Error
    logic [7:0]   		w_eth_mii_rx_data;		// Internal Rx Data
    
    ...
      
    assign w_eth_mii_rx_clk = i_eth_mii_rx_clk;
    
    ...
    
    IDDR #(
        .DDR_CLK_EDGE ( "SAME_EDGE_PIPELINED"     ),                                     
        .INIT_Q1      ( 1'b0                      ), 
        .INIT_Q2      ( 1'b0                      ), 
        .SRTYPE       ( "SYNC"                    ) 
    ) m_IDDR_eth_mii_rx_en (
        .Q1           ( w_eth_mii_rx_ctl[0]       ), 
        .Q2           ( w_eth_mii_rx_ctl[1]       ), 
        .C            ( w_eth_mii_rx_clk          ),   
        .CE           ( 1'b1                      ), 
        .D            ( i_eth_mii_rx_ctl          ),   
        .R            ( w_eth_mii_rx_rst          ),   
        .S            ( 1'b0                      )    
    );
    
    assign w_eth_mii_rx_en = w_eth_mii_rx_ctl[0];
    assign w_eth_mii_rx_err = w_eth_mii_rx_ctl[1] ^ w_eth_mii_rx_ctl[0];
    
    genvar et;
    generate
      for (et = 0; et < 4; et = et + 1) begin
          IDDR #(
            .DDR_CLK_EDGE ( "SAME_EDGE_PIPELINED"     ),                                     
            .INIT_Q1      ( 1'b0                      ), 
            .INIT_Q2      ( 1'b0                      ), 
            .SRTYPE       ( "SYNC"                    ) 
          ) m_IDDR_eth_mii_rx_data (
            .Q1           ( w_eth_mii_rx_data[et + 0] ), 
            .Q2           ( w_eth_mii_rx_data[et + 4] ), 
            .C            ( w_eth_mii_rx_clk          ),   
            .CE           ( 1'b1                      ), 
            .D            ( i_eth_mii_rx_data[et]     ),   
            .R            ( w_eth_mii_rx_rst          ),   
            .S            ( 1'b0                      )    
          );
      end
    endgenerate
    # Top constraints file
    
    ...
      
    ## Ethernet PHY
    set_property -dict { PACKAGE_PIN AK16  IOSTANDARD LVCMOS18 } [get_ports { i_eth_int_b }];
    set_property -dict { PACKAGE_PIN AK15  IOSTANDARD LVCMOS18 } [get_ports { i_eth_pme_b }];
    set_property -dict { PACKAGE_PIN AH24  IOSTANDARD LVCMOS33 } [get_ports { o_eth_phy_rstn }];
    set_property -dict { PACKAGE_PIN AF12  IOSTANDARD LVCMOS15 } [get_ports { o_eth_mii_mdc }];
    set_property -dict { PACKAGE_PIN AG12  IOSTANDARD LVCMOS15 } [get_ports { t_eth_mii_mdio }];
    set_property -dict { PACKAGE_PIN AE10  IOSTANDARD LVCMOS15 } [get_ports { o_eth_mii_tx_clk }];
    set_property -dict { PACKAGE_PIN AK14  IOSTANDARD LVCMOS15 } [get_ports { o_eth_mii_tx_ctl }];
    set_property -dict { PACKAGE_PIN AJ12  IOSTANDARD LVCMOS15 } [get_ports { o_eth_mii_tx_data[0] }];
    set_property -dict { PACKAGE_PIN AK11  IOSTANDARD LVCMOS15 } [get_ports { o_eth_mii_tx_data[1] }];
    set_property -dict { PACKAGE_PIN AJ11  IOSTANDARD LVCMOS15 } [get_ports { o_eth_mii_tx_data[2] }];
    set_property -dict { PACKAGE_PIN AK10  IOSTANDARD LVCMOS15 } [get_ports { o_eth_mii_tx_data[3] }];
    set_property -dict { PACKAGE_PIN AG10  IOSTANDARD LVCMOS15 } [get_ports { i_eth_mii_rx_clk }];
    set_property -dict { PACKAGE_PIN AH11  IOSTANDARD LVCMOS15 } [get_ports { i_eth_mii_rx_ctl }];
    set_property -dict { PACKAGE_PIN AJ14  IOSTANDARD LVCMOS15 } [get_ports { i_eth_mii_rx_data[0] }];
    set_property -dict { PACKAGE_PIN AH14  IOSTANDARD LVCMOS15 } [get_ports { i_eth_mii_rx_data[1] }];
    set_property -dict { PACKAGE_PIN AK13  IOSTANDARD LVCMOS15 } [get_ports { i_eth_mii_rx_data[2] }];
    set_property -dict { PACKAGE_PIN AJ13  IOSTANDARD LVCMOS15 } [get_ports { i_eth_mii_rx_data[3] }];
    
    ## Clocks
    create_clock -add -name CLK_ETH_MII_RX -period 8.00 -waveform {0.0 4.0} [get_ports {i_eth_mii_rx_clk}];
    
    create_generated_clock -name CLK_25MHZ        [get_pins m_MMCME2_BASE/CLKOUT1]
    create_generated_clock -name CLK_50MHZ        [get_pins m_MMCME2_BASE/CLKOUT3]	# Design Cock
    create_generated_clock -name CLK_125MHZ       [get_pins m_MMCME2_BASE/CLKOUT4]	# Tx Clock
    create_generated_clock -name CLK_125MHZ_P90   [get_pins m_MMCME2_BASE/CLKOUT5]	# Tx Clock with 90 Phase Shift
    create_generated_clock -name CLK_500MHZ       [get_pins m_MMCME2_BASE/CLKOUT6]	# ILA Clock
    
    set_clock_groups -asynchronous -group {CLK_50MHZ CLK_ETH_MII_RX CLK_125MHZ}

    After several checks, I seem to have used the same blocks (IDDR) and constraints as in the examples I've seen. However, what I'm observing doesn't seem to be consistent with what I expected. Any idea what I might have missed as a problem or constraint? I'm pretty sure it must be an obvious problem, but impossible for me to identify it ...
    Thanks for your help!

     

     

  2. 17 hours ago, zygot said:
    Quote

    Thanks for you answer: I'll take a closer look on this post to make sure I haven't missed anything.
     

    Quote

    First, you've gotten a basic design to work in a manner similar to what the tutorial presents, yes? If not that's the place to start.

    The Mig IP nice because it gives you all of the sources in Verilog. It and the example project, unfortunately, are written in as obtuse and difficult to rost out manner as possible. Trying to turn it into a multi-channel DDR controller is going to be difficult. The first phase of pain will be to simulate the working vanilla Mig-based design as a baseline. You will have to do your design in Verilog. If you can't work out how to do that step, then you are in for some hard times. This is the only rational way to know if your own Verilog modules are working as expected.

    Just to to be sure that I am clear on my issue: I'm not trying to redesign a more complex MIG. I am just using the one available on Vivado which has one use interface port. It's in my own system where I have a module which receives requests coming from two ports and tries to redirect them to the one MIG port. It acts like a "multiplexer" with priorities. That's why I am surprised when I see the MIG not responding after many cycles while it seems to work fine in the beginning of the execution ...
     

    Quote

     


    Debugging a complex design using the ILA is going to be a slow and arduous sled ride.


    If you can't do that step then you will have to slog through the IP code and instrument it. Starting from something that doesn't work is most likely going to take more time than starting with something that does work and that you can enhance bit by bit.

    If you are interacting with the Mig controller properly I wouldn't expect to see the kinds of behavior that you are experiencing. That kind of points to your VDMA code. The Mig has a debug feature that you might want to enable. This may or may not help. I suspect that you are expecting the DDR controller to operate in a linear manner, and that is probably not what it is doing. If you aren't managing all of the read/write bytes per burst operation this would lead to problems. If you aren't monitoring fault or error signals deep within the IP then it's going to be hard to figure out what's going on using an ILA. The ILA isn't ideal for all debugging needs. Sometimes you have to create your own LA IP to capture elusive events and present them in a form that you can understand.

     

    I am not sure to understand how I can debug the design without the ILA here: simulate my own design with MIG seems completely impossible and I do not have any other way to observe signals during execution ...

    However, I did not try to use the debug feature of the MIG. If I understand correctly, it adds some signals to the MIG interface (dbg_*) which allow to view internal states of the MIG. Am I right ?

     

  3. I am currently trying to implement an interface between multiple ports of a custom memory bus and the MIG IP of my Arty A7-35T board.Basically in my current example design, the first port reads a memory range 128-bit by 128-bit (it is for a custom VDMA). In the same time, the second port writes values in the same memory range (it is to emulate a CPU activity). The first port has the priority: if it is not busy, it sends its read request and else, its the second port which tries to write. I try to debug my design with an ILA.

    (See picture normal_read) In the first cycles after the reset, the system looks to work as expected. The app_rd_valid is asserted some cycles after the request (r_rpend indicates how many read requests are pending, r_mig_not is simply used to try to visualize the clock, r_mig_cycle indicates the number of cycles since the last reset).

    But later during the execution, the whole system seems to be locked (or slowed down). Particularly, the MIG becomes really slow during read requests. We can see (on pictures rpend_increase and long_read) that app_rd_valid is now asserted only after many cycles (512+ cycles if we consider the r_mig_cycle[15:8]) while the app_rdy is high. This hypothesis is validated by the value of r_mig_rpend which stays at 7 most of the time ... Finally, it seems that the MIG does not respond at all to my read requests since the trigger on app_rd_valid is never activated again.

    I thought that the MIG asserts a read request in only some cycles (~22 cycles). Is that correct ? Do you have any ideas of what conditions I have possibly missed which leads to this strange working ? Or a possible strategy to debug my design ?

    Thanks for your help!

    long_read.png

    normal_read.png

    rpend_increase.png

×
×
  • Create New...