cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
noreeli79
Adventurer
Adventurer
310 Views
Registered: ‎11-04-2015

How to implement ddr and sdr

Jump to solution

Hi,

I want to implement a DDR input stage, which seems to be OK with the following code.

Now I want to add the possibility to switch dynamically between a DDR and an SDR mode (port 'Mode'), the external chip does support both modes so I have to support both modes which are switchable during runtime.

For the purpose of SDR I add extra constraints (from external chip datasheet) for setup/hold analysis (in constraint file: dv_bre_sdr, dv_are_sdr)
The problem I get with these extra constraints is that timing closure is not ok anymore. In my opinion setup constraints for DDR are tighter, so why do the extra SDR constraints corrupt the situation?

 

 

 

library ieee;
use ieee.std_logic_1164.all;

library unisim;
use unisim.vcomponents.all;

entity ddr_in is
port(
    CLK         : in std_logic;
    REFCLK_p    : in std_logic;
    REFCLK_n    : in std_logic;
    D           : in std_logic;
    RESET       : in std_logic;
    Q           : out std_logic_vector(1 downto 0);
    Mode        : in  std_logic
);
end;


architecture beh of ddr_in is

signal clk_bufio    : std_logic;
signal clk_bufg     : std_logic;
signal l_q1         : std_logic;
signal l_q2         : std_logic;
signal refclk_ibuf  : std_logic;
signal refclk_bufg  : std_logic;

signal CNTVALUEOUT  : std_logic_vector(4 downto 0);
signal DATAOUT      : std_logic;
signal CE           : std_logic := '1';
signal CINVCTRL     : std_logic := '0';
signal CNTVALUEIN   : std_logic_vector(4 downto 0) := "00000";
signal DATAIN       : std_logic := '0';
signal INC          : std_logic := '0';
signal LD           : std_logic := '0';
signal LDPIPEEN     : std_logic := '0';    
signal RDY          : std_logic;

begin


process(clk_bufg)
begin
    if rising_edge(clk_bufg) then
        if Mode = '1' then
            Q <= l_q2 & l_q1;      -- DDR
        else
            Q <= '0' & l_q1;       -- SDR    
            --Q <= '0' & D;        -- ????? Should I use the input instead? 
        end if;    
    end if;

end process;


clk_bg : BUFG
port map(I => CLK, O => clk_bufg);

clk_b : BUFR
port map(I => CLK, CE => '1',  CLR => '0', O => clk_bufio);



i_refclk_ibufds: IBUFGDS
generic map (
    DIFF_TERM    => FALSE,
    IBUF_LOW_PWR => TRUE,
    IOSTANDARD   => "DEFAULT"
)
port map (
    I   => REFCLK_p,
    IB  => REFCLK_n,
    O   => refclk_ibuf
);


refclk_bg : BUFG
port map(I => refclk_ibuf, O => refclk_bufg);


i_ddr : IDDR
generic map (   
    DDR_CLK_EDGE => "SAME_EDGE",  
    INIT_Q1      => '0',          
    INIT_Q2      => '0',          
    SRTYPE       => "ASYNC"       
)                                 
port map (                        
    Q1  => l_q1,                  
    Q2  => l_q2,                  
    C   => clk_bufio,             
    CE  => '1',                   
    D   => DATAOUT,               
    R   => RESET,                 
    S   => '0'                    
);

i_del : IDELAYE2
generic map (
    CINVCTRL_SEL            => "FALSE",    
    DELAY_src=> "IDATAIN",  
    HIGH_PERFORMANCE_MODE   => "FALSE",    
    IDELAY_TYPE             => "FIXED",    
    IDELAY_VALUE            => 5,          
    PIPE_SEL                => "FALSE",    
    REFCLK_FREQUENCY        => 200.0,      
    SIGNAL_PATTERN          => "DATA"      
)
port map (
    CNTVALUEOUT => CNTVALUEOUT,         
    DATAOUT     => DATAOUT,             
    C           => clk_bufio,           
    CE          => CE,                  
    CINVCTRL    => CINVCTRL,            
    CNTVALUEIN  => CNTVALUEIN,          
    DATAIN      => DATAIN,              
    IDATAIN     => D,                   
    INC         => INC,                 
    LD          => LD,                  
    LDPIPEEN    => LDPIPEEN,            
    REGRST      => RESET                
);



i_delctrl : IDELAYCTRL
port map (
    RDY     => RDY,         
    REFCLK  => refclk_bufg, 
    RST     => RESET        
);



end architecture;

 

 

Constraint-File:

 

 

 

create_clock -period 6.7 -name TheClk [get_ports {CLK}]
create_clock -period 5.0 -name TheRefClk [get_ports {REFCLK_p}]
set_property PACKAGE_PIN U16 [get_ports "RESET"]
set_property PACKAGE_PIN R22 [get_ports "CLK"]
set_property PACKAGE_PIN P24 [get_ports "D"]
set_property PACKAGE_PIN AA9 [get_ports "REFCLK_p"]
set_property PACKAGE_PIN AB9 [get_ports "REFCLK_n"]

# Center-Aligned Double Data Rate Source Synchronous Inputs 
#
# For a center-aligned Source Synchronous interface, the clock
# transition is aligned with the center of the data valid window.
# The same clock edge is used for launching and capturing the
# data. The constraints below rely on the default timing
# analysis (setup = 1/2 cycle, hold = 0 cycle).
#
# input                  ____________________
# clock    _____________|                    |_____________
#                       |                    |                 
#                dv_bre | dv_are      dv_bfe | dv_afe
#               <------>|<------>    <------>|<------>
#          _    ________|________    ________|________    _
# data     _XXXX____Rise_Data____XXXX____Fall_Data____XXXX_
#

set input_clock         TheClk;            # Name of input clock
set input_clock_period  6.7;               # Period of input clock (full-period)
set dv_bre              1.2;               # Data valid before the rising clock edge
set dv_are              1.0;               # Data valid after the rising clock edge
set dv_bfe              1.42;              # Data valid before the falling clock edge
set dv_afe              0.84;              # Data valid after the falling clock edge
set input_ports         "D";               # List of input ports

set dv_bre_sdr          2.88;               # Data valid before the rising clock edge, SDR
set dv_are_sdr          1.88;               # Data valid after the rising clock edge, SDR

# Input Delay Constraint (DDR)
set_input_delay -clock $input_clock -max [expr $input_clock_period/2 - $dv_bfe] [get_ports $input_ports];
set_input_delay -clock $input_clock -min $dv_are                                [get_ports $input_ports];
set_input_delay -clock $input_clock -max [expr $input_clock_period/2 - $dv_bre] [get_ports $input_ports] -clock_fall -add_delay;
set_input_delay -clock $input_clock -min $dv_afe                                [get_ports $input_ports] -clock_fall -add_delay;

# Input Delay Constraint (SDR)
set_input_delay -clock $input_clock -max [expr $input_clock_period - $dv_bre_sdr] [get_ports $input_ports] -add_delay;
set_input_delay -clock $input_clock -min $dv_are_sdr                              [get_ports $input_ports] -add_delay;

 

 

 

 

I am using Vivado 2019.2

 

Cheers, Noreeli

0 Kudos
1 Solution

Accepted Solutions
avrumw
Guide
Guide
132 Views
Registered: ‎01-23-2009

Why does Vivado list them? I mean they have the same properties as "TheClk"...

They are different clocks objects and there are paths between them so they are "Inter-Clock". That's all this says - the rules for timing "Inter" and "Intra" clocks are actually the same; the tool is just separating them for convenience. Since the two clocks are identical in specification, the timing would be identical to if we had used the same clock, except it would have been listed as "Intra-Clock".

Avrum

View solution in original post

5 Replies
avrumw
Guide
Guide
263 Views
Registered: ‎01-23-2009

In my opinion setup constraints for DDR are tighter, so why do the extra SDR constraints corrupt the situation?

The DDR constraints look tighter when you only look at them from the artificial perspective of the are/bre/afe/bfe notation introduced by the timing wizards. But when you look at them from the "real" perspective of the set_input_delay they are not.

Lets look at the bre

For the set_input_delay -max for the DDR and the SDR these are

  • DDR: $input_clock_period/2 - $dv_bfe = 6.7/2 - 1.2 = 2.15ns
  • SDR: $input_clock_period    - $dv_bfe_sdr = 6.7 - 2.88 = 3.85ns

So the tools have two set_input_delay -max commands with respect to the rising edge of the clock one at 2.15ns and one at 3.85ns. It uses both for both SDR and DDR destinations - clearly the 3.85ns from the rising edge of the clock fails.

Avrum

noreeli79
Adventurer
Adventurer
217 Views
Registered: ‎11-04-2015

Thank you for your explanation. How could I achieve that the SDR constraints are only applied to a path which is not DDR relevant?

In the VHDL file there is the comment "?Should I use the input instead?" How could I define a SDR constraint which only checks the path which would not go

through IDELAYE2 and IDDR, that is the assignment of "Q" in SDR mode?

Rgds, Noreeli

0 Kudos
avrumw
Guide
Guide
189 Views
Registered: ‎01-23-2009

Based on your code and the question in the comment you have two possible capture mechanism. I will start with the one that is commented out ""Should I use the input instead". For this one your capture mechanism is:

  • D comes in through a port
  • Goes through an IBUF  (inferred - not instantiated)
  • Splits off into two paths
    • Path 1 - only used in DDR mode:
      • Goes through an IDELAY (DATAOUT)
      • Goes to an IDDR (l_q1 and l_q2)
    • Path 2 - only used in SDR mode:
      • Goes straight to a clocked VHDL process which implements a flip-flop (Q clocks D directly)

If this is the case, then it is possible to separate the SDR and DDR constraints because they have separate capture mechanism - the endpoints of the static timing paths are different for the SDR and DDR mode.

But...

This kind of structure isn't highly recommended. Your DDR capture path is fine; the capture is done in the IDDR which is packed into the Input/Output Block (IOB) - i.e. it is tightly associated with the IBUF. But your SDR capture path will use a fabric flip-flop - it will leave the IOB go into the general fabric routing and be captured in a slice flip-flop there. Capturing an input in a fabric flip-flop is slower (needs bigger data valid windows), but is also variable - the timing characteristics of this will change on each implementation run. It is primarily because of this that it is recommended to capture input interfaces in the IOB - either in the IDDR/ISERDES or in the IOB flip-flop. However, you cannot use both the IDDR/ISERDES and the IOB flip-flop at the same time (they are really the same thing).

In the second capture structure, which is actually implemented (not commented out), the IDDR samples the signal on both the rising edge and the falling edge of the clock and put out values on l_q1 and l_q2. In DDR mode, you use both of them. In SDR mode you simply ignore l_q2 - yes, the timing of the Q2 capture may fail (so Q2 could even go metastable), but your MUX with Mode gates out l_q2, so this should be harmless. This is a more reliable capture mechanism. 

However when done this way, both captures (SDR and DDR) go through the IDELAY - this is different than the previous capture where only the DDR went through the IDELAY.

But, you have a problem here. The IDDR is captured on a clock generated by a BUFR (clk_bufio), but "Q" is clocked on a clock generated by a BUFG (clk_bufg). You should not be transferring data between a BUFR domain and a BUFG domain; the clock skew between these two domains is very large. At low frequencies, the tools can probably manage this - the will fix the large hold time violation due to the skew and still be able to meet the setup requirement. But at higher frequencies this will be impossible. It will also depend on what device this is - it will be able to go faster on a smaller device than on a larger device - the delay on a BUFR is the same in all devices, but the delay of the BUFG grows as the device gets bigger. I am a very surprised it works at 150MHz DDR - the path from l_q2 to Q_reg is a 2.5ns path with lots of clock skew - do you have any timing violations on this path?

Now for constraints.

To start with you will need at least one virtual clock. A virtual clock is a clock that is used only for constraints - it does not get applied to any pin/port/net in the design. In Vivado all clocks are related by default so defining a virtual clock that has the same attributes as your real clock doesn't change timing; timing paths between the virtual and real clock are analyzed the same way they would be if they were both using the same real clock. For clarity, I am actually going to define two virtual clocks - one for the SDR constraints and one for the DDR constraints. So you would have

create_clock -period 6.7 -name TheClk [get_ports {CLK}]
create_clock -period 6.7 -name virtClk_sdr
create_clock -period 6.7 -name virtClk_ddr

Now set your SDR constraints with respect to virtClk_sdr and your DDR constraints wrt. virtClk_ddr

 

# Input Delay Constraint (DDR)
set_input_delay -clock virtClk_ddr -max [expr $input_clock_period/2 - $dv_bfe] [get_ports $input_ports];
set_input_delay -clock virtClk_ddr -min $dv_are                                [get_ports $input_ports];
set_input_delay -clock virtClk_ddr -max [expr $input_clock_period/2 - $dv_bre] [get_ports $input_ports] -clock_fall -add_delay;
set_input_delay -clock virtClk_ddr -min $dv_afe                                [get_ports $input_ports] -clock_fall -add_delay;

# Input Delay Constraint (SDR)
set_input_delay -clock virtClk_sdr -max [expr $input_clock_period - $dv_bre_sdr] [get_ports $input_ports] -add_delay;
set_input_delay -clock virtClk_sdr -min $dv_are_sdr                              [get_ports $input_ports] -add_delay;

 

Now you need to disable the timing on the paths that aren't real. Lets take the commented out code first - it is clearer.

The DDR path is from the input clock to the IDDR, the SDR path is from the input clock to the Q_reg flip-flop

set_false_path -from [get_clocks virtClk_ddr] -to [get_cells Q_reg[*]]; # disable the DDR constraints to the SDR capture
set_false_path -from [get_clocks virtClk_sdr] -to [get_cells i_ddr]; # disable SDR constraints to the DDR capture

For the one that you have implemented now (not commented it) it is a little less clean. What you want to do is disable the SDR constraints to the capture that occurs on the DDR on the falling edge. Assuming virtClk_sdr is not used anywhere else then this can be done by

set_false_path -from [get_clocks virtClk_sdr] -fall_to [get_clocks TheClk]

(I think this should work...)

Avrum

noreeli79
Adventurer
Adventurer
154 Views
Registered: ‎11-04-2015

One question regarding the virtual clocks: When looking into the Timing Summary I can see that in the section "Inter-Clock Paths" the virtual clocks are listed:
virtClk_ddr to TheClk

virtClk_sdr to TheClk

Why does Vivado list them? I mean they have the same properties as "TheClk"...

Rgds, Noreeli

0 Kudos
avrumw
Guide
Guide
133 Views
Registered: ‎01-23-2009

Why does Vivado list them? I mean they have the same properties as "TheClk"...

They are different clocks objects and there are paths between them so they are "Inter-Clock". That's all this says - the rules for timing "Inter" and "Intra" clocks are actually the same; the tool is just separating them for convenience. Since the two clocks are identical in specification, the timing would be identical to if we had used the same clock, except it would have been listed as "Intra-Clock".

Avrum

View solution in original post