Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
12 years ago

Multi cycle path trough combinatoric logic circuit

Hi, i have an issue to fully understand and constraint multi cycle path for particular vhdl file.

I created pipeline tree adder with enable input. This pipeline tree adder is created using recursion approach (see VHDL code).

Enable signal is used to reduce calculation speed of this digital circuit, by allowing pipeline data to change only when enable signal's value is high.

Such approach is used because the main system's clock is higher than the input data rate. Enable signal appears only once in every fifth clock (as fast as the input data), thus reducing the calculation speed by 5x times, allowing this circuit to work in the same clock domain as the main circuit.


library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library lib_packages;
use lib_packages.util_pkg.all;
library arith;
use arith.arith_lib.all;
library altera;
use altera.altera_primitives_components.all;
entity pipeline_tree_adder_signed_with_en is
    generic
    (
        P            : natural := 4;        -- Number of inputs
        DATA_WIDTH    : natural := 1        -- Data width
    );
    port
    (
        clk            : in std_logic;
        wr_req_in    : in std_logic;
        en_in        : in std_logic;
        data_in_2d    : in std_logic_2d(P-1 downto 0, DATA_WIDTH-1 downto 0);
        data_out    : out std_logic_vector(DATA_WIDTH-1+log2c(P) downto 0);
        wr_req_out    : out std_logic
    );
end entity;
architecture rtl of pipeline_tree_adder_signed_with_en is
    subtype ubyte        is signed(DATA_WIDTH-1 downto 0);
    type u_1d_array        is array(natural range <>) of ubyte;
    subtype ubytew        is signed(DATA_WIDTH downto 0);
    type u_1d_array_w    is array(natural range <>) of ubytew;
    signal data_1d_reg, data_1d_next    : u_1d_array(P-1 downto 0);
    signal sum_1d                         : u_1d_array_w(((P-(P mod 2))/2 + (P mod 2))-1 downto 0);
    signal sum_2d                        : std_logic_2d(((P-(P mod 2))/2 + (P mod 2))-1 downto 0, DATA_WIDTH downto 0);
    signal wr_req_in_reg, wr_req_tmp_reg, wr_req_tmp    : std_logic := '0';
    signal output_signal        : std_logic_vector(DATA_WIDTH-1+log2c(P) downto 0) := (others => '0');
    signal en_temp                : std_logic := '0';
    component signed_adder is
        generic
        (
            DATA_WIDTH : natural
        );
        port 
        (
            a           : in signed  (DATA_WIDTH-1 downto 0);
            b           : in signed  (DATA_WIDTH-1 downto 0);
            result    : out signed (DATA_WIDTH-1 downto 0)
        );
        end component;
begin
    process(data_in_2d)
    begin
        for i in P-1 downto 0 loop
            for l in DATA_WIDTH-1 downto 0 loop
                data_1d_next(i)(l)        <= data_in_2d(i, l);
            end loop;
        end loop;
    end process;
    process(clk)
    begin
        if rising_edge(clk) then
            if (en_in = '1') then
                wr_req_in_reg    <= wr_req_in;
            else
                wr_req_in_reg    <= wr_req_in_reg;
            end if;
        end if;
    end process;
    
    en_temp <= en_in and wr_req_in;
    
    -- component's
    process(clk)
    begin
        if rising_edge(clk) then
            if (en_temp = '1') then
                data_1d_reg <= data_1d_next;
            else
                data_1d_reg    <= data_1d_reg;
            end if;
        end if;
    end process;
    sadder_gen :
    for i in 0 to ((P-(P mod 2))/2-1) generate
        sadder : signed_adder
        generic map (DATA_WIDTH => (DATA_WIDTH+1))
        port map (a => (data_1d_reg(i*2)((data_1d_reg(i*2)'length)-1) & data_1d_reg(i*2)), b => (data_1d_reg(i*2+1)((data_1d_reg(i*2+1)'length)-1) & data_1d_reg(i*2+1)), result => sum_1d(i));
    end generate;
    --1. if P = 2
        Output_stage_gen:
        if (P = 2) generate
            output_signal    <= std_logic_vector(sum_1d(0));
            wr_req_out        <= wr_req_in_reg;
        end generate;
        int_gen:
        if (P > 2) generate
            process(sum_1d)
            begin
                for i in (((P-(P mod 2))/2 + (P mod 2))-1) downto 0 loop
                    for l in DATA_WIDTH downto 0 loop
                        sum_2d(i,l)        <= sum_1d(i)(l);
                    end loop;
                end loop;
            end process;
            Even_stage_gen:
            if (P mod 2 = 0) generate
                even_gen: pipeline_tree_adder_signed_with_en
                    generic map (P => P/2, DATA_WIDTH => DATA_WIDTH + 1)
                    port map (clk => clk, wr_req_in => wr_req_in_reg, en_in => en_in, data_in_2d => sum_2d, data_out => output_signal, wr_req_out => wr_req_out);
            end generate;
            Odd_stage_gen:
            if (P mod 2 = 1) generate
                sum_1d(((P-(P mod 2))/2 + (P mod 2))-1) <= data_1d_reg(P-1)((data_1d_reg(P-1)'length)-1) & data_1d_reg(P-1);
                odd_gen: pipeline_tree_adder_signed_with_en
                    generic map (P => (P-1)/2+1, DATA_WIDTH => DATA_WIDTH + 1)
                    port map (clk => clk, wr_req_in => wr_req_in_reg, en_in => en_in, data_in_2d => sum_2d, data_out => output_signal, wr_req_out => wr_req_out);
            end generate;
        end generate;
    data_out    <= output_signal;
end architecture;

Respective VHDL RTL:

https://www.alteraforum.com/forum/attachment.php?attachmentid=8322

My question is: how do i constraint multi cycle path for such design where is one common clock with short enable impulses. How to correctly specify in SDC file that enable_in signal appears every fifth clock cycle and is only 1 clock cycle long?

See timing diagrams.

https://www.alteraforum.com/forum/attachment.php?attachmentid=8323

To constraint multi cycle path i have been using such SDC command, but it didn't work...

# set_multicycle_path 3 -to [get_fanouts [get_pins -hier *en*|q*] -through [get_pins -hier *|*ena*]]

In top level entity i have register what generates enable impulses.

Regards,

Rinalds

7 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    What you need to do, is set the setup and hold times either "from" the input registers or "to" the output registers (or from and to if you only want specified paths.

    set_multicycle_path -from [get_keepers {my_input_regeres} ] -to [get_keepers {my_output_registers}] -setup N

    set_multicycle_path -from [get_keepers {my_input_regeres} ] -to [get_keepers {my_output_registers}] -hold N-1

    This is when enable is high once every N clocks.

    I notice the data out from your blcok is not registered - any reason?
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Another question - why have you made the design more complex that it needs to be? why not just put

    a <= b + c;

    in this code, rather than making a signed adder component?
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    If your question was - why i need additional register between adders, when answer is to increase speed. In real design input number may achieve more than 32 inputs and each input could be more than 18bit width.

    If Your question was - why i use adder as a separate component when answer is to simplify recursion realization, in this way a can easily pass through generic values. Maybe there are different ways of creating such designs, but i simply don't know them ;)

    In this VHDL code i need only change generic values and Quartus II software generates required stages to sum all input values (tree shaped architecture). Input values can bee even or odd.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Thanks for fast replay.

    I will start with easy part.

    --- Quote Start ---

    I notice the data out from your blcok is not registered - any reason?

    --- Quote End ---

    Output data will be registered in the next module.

    --- Quote Start ---

    What you need to do, is set the setup and hold times either "from" the input registers or "to" the output registers (or from and to if you only want specified paths.

    set_multicycle_path -from [get_keepers {my_input_regeres} ] -to [get_keepers {my_output_registers}] -setup N

    set_multicycle_path -from [get_keepers {my_input_regeres} ] -to [get_keepers {my_output_registers}] -hold N-1

    This is when enable is high once every N clocks.

    --- Quote End ---

    Yea it helped, but with some modifications:

    I looked in Altera home page and finally found SDC example where enable signals was used.

    http://www.altera.com/support/examples/timequest/exm-tq-clock-enable.html#figure1 (http://www.altera.com/support/examples/timequest/exm-tq-clock-enable.html#figure1)

    Applied same technique to my design and get such result

    set_multicycle_path -to [get_fanouts [get_pins -hier *en_in*] -through [get_pins -hier *|*ena*]] -setup 5

    set_multicycle_path -to [get_fanouts [get_pins -hier *en_in*] -through [get_pins -hier *|*ena*]] -hold 4

    https://www.alteraforum.com/forum/attachment.php?attachmentid=8324

    So is it correct? To my mind yes!
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    No, the question is why is there no register after the adder at the output? Its usually best practice to have a register as the last bit of logic before a signal leaves a block.

    I just feel simple components (like a single adder) help obfuscate the design heirarchy, when a simple + function can be used. I dont understand the relevance of the inputs being odd or even?

    Altera already provides a parrellel add megafunction:

    http://www.altera.co.uk/literature/ug/ug_lpm_alt_mfug.pdf
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    I dont understand the relevance of the inputs being odd or even?

    --- Quote End ---

    It means what designed pipeline tree adder module can be even or odd count of inputs. No modifications are needed in VHDL code.

    RTL with 3 inputs

    https://www.alteraforum.com/forum/attachment.php?attachmentid=8334

    RTL with 4 inputs

    https://www.alteraforum.com/forum/attachment.php?attachmentid=8335

    Yes i know what Altera provides with huge set of megafunctions. But i wanted to raise my skill in VHDL - so i started to build my own basic blocs.

    P.S. sorry about my English.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Ok: Challenge for you to help improve your VHDL further:

    1. Try and re-write this block without your custom adder component

    2. Now try it without using the hellish type that is altera's "std_logic_2d" type (hint: create you own type). Even preferably avoid std_logic_vector completly for any numerical values (it just adds to type conversions).

    The std_logic_2d type was creates by altera to try and be compatible with their graphical design files and AHDL. It is horrible to use, as you have found out as you have to pick it apart bit by bit.