Showing results for 
Show  only  | Search instead for 
Did you mean: 
Registered: ‎09-30-2019

timing constraints on inferred RAM (Block or Distributed)

to easy flexible inclusion of RAMs, both Block or Distributed, in our designs, I designed some VHDL modules to infer generic single port, simple dual port and dual port memories. 
Some generic parameters allow to specify geometry, read synchronous/asynchronous, memory type and so on. 

For instance, I designed module


entity RAM_SDP_generic is
    generic (
        WIDTH: natural;
        SIZE: natural;
        B_MODE: string;  -- "ASYNC", "SYNC"
        RAM_TYPE: string; -- "DISTRIBUTED", "BLOCK", "ULTRA"
    port (
        A_clock_in: in STD_LOGIC;
        A_write_enable_in: in STD_LOGIC;
        A_address_in: in STD_LOGIC_VECTOR(CeilLog2(SIZE)-1 downto 0);
        A_data_write_in: in STD_LOGIC_VECTOR(WIDTH-1 downto 0);
        B_reset_in: in STD_LOGIC;
        B_clock_in: in STD_LOGIC;
        B_enable_in: in STD_LOGIC;
        B_address_in: in STD_LOGIC_VECTOR(CeilLog2(SIZE)-1 downto 0);
        B_data_read_out: out STD_LOGIC_VECTOR(WIDTH-1 downto 0)
end RAM_SDP_generic;



Internally RAM is implemented as from inference templates:

        if rising_edge(A_clock_in) then
            if (A_write_enable_in='1') then
                RAM(TO_INTEGER(UNSIGNED(A_address_in))) <= A_data_write_in;
            end if;
        end if;
    end process;
    -- asychronous read (only for distributed RAM)
    if (B_MODE="ASYNC") generate
        B_data_read <= RAM(TO_INTEGER(UNSIGNED(B_address_in)));
    end generate;

    -- synchronous read
    if (B_MODE="SYNC") generate
            if rising_edge(B_clock_in) then
                if (B_enable_in='1') then
                    B_data_read <= RAM(TO_INTEGER(UNSIGNED(B_address_in)));
                end if;
            end if;
        end process;
    end generate;

    B_data_read_out <= B_data_read;


In VHDL modules employing these RAM modules as boundary between two clocks (write synchronous, read asynchronous or synchronous), I need to write effective timing constraints rules to cover all possible cases.

For example, in a module where RAM is instanced with name "inst_RAM_SDP_write_toggle", RAM write clock "A_clock_in" is connected to signal "clock_in" and read clock "B_clock_in" is connected to "s_lb_clock_in", I specified a rule in this way


set_false_path -from [get_clocks -of_objects [get_ports clock_in]] -through [get_cells inst_RAM_SDP_write_toggle/RAM_reg*] -to [get_clocks -of_objects [get_ports s_lb_clock_in]]



This rule somehow works and timing errors are cleared, however I'm not sure if it is the best way to specify timing isolation between two clocks crossing inferred RAM,
keeping in consideration that for distributed RAM and large geometries several RAMxxx slices plus severals LUTs are employed, all of them are named RAM_reg_xxx by synthesis.
I would be really sure that timing ignore remains located in the asynchronous read section of the inferred RAM, so both synchronous and asynchronous read will be correctly constrained with reference to read clock.
This should be true as I specified both write and read clocks are specified.

Furthermore, how could I modify the rule to "disable" timing ignore when top module is employed with same clock on both write and read sides, so both "clock_in" and "s_lb_clock_in" are actually connected to the same clock?



0 Kudos
0 Replies