Search code examples
vhdl

Design does not finish synthesizing after 4 hours


In my design I have a matrix of 1024 integers. Under certain circumstances, I need to increase the value of some of these integers in a unit. The problem is that I cannot make this design finish synthesizing, I have waited more than four hours and it still does not end or returns an error.

Previously I had a code that synthesized in a few minutes, but when I added this (actually a very similar one), he spent more than 12 hours synthesizing and never finished.

I hope you can help me, I am finishing my degree work and I have not been able to finish it because of this problem.

Thank you

The design is as follows:

use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity Proof_Array is
  Port (
    reset                  :   in  std_logic;
    Peak_height_detected_1 :   in  std_logic_vector(9 downto 0);
    Add_this_height        :   in  std_logic;
    S_clk_ADC_15MHz        :   in  std_logic;
    S_Out                  :   out std_logic_vector(31 downto 0));
end Proof_Array;

architecture Behavioral of Proof_Array is
    type PHA_Array_Type is array (0 to 1023) of integer;
    signal PHA_Array: PHA_Array_Type;
    signal number: integer range 0 to 1023;

    signal Peak_height_detected_1_int: integer range 0 to 1023;
begin
    Peak_height_detected_1_int <= to_integer(unsigned(Peak_height_detected_1));
    S_Out <= std_logic_vector(to_unsigned(PHA_Array(number), S_Out'length));

    process(reset, S_clk_ADC_15MHz)    
    begin
        if reset = '1' then 
            for k in 0 to 1023 loop 
                PHA_Array(k) <= 0; 
            end loop;
        elsif rising_edge(S_clk_ADC_15MHz) then
            if Add_this_height = '1' then
                PHA_Array(Peak_height_detected_1_int) <= PHA_Array(Peak_height_detected_1_int) + 1;
            end if;
            if number > 1022 then 
                number <= 0;
            else 
                number <= number + 1;
            end if;
        end if;    
    end process;```

Solution

  • You don't say what tool you are using for synthesis, or even whether the target device is an FPGA, ASIC or something else. However, the short answer is that I think you will probably be able to achieve what you are trying to do - but I think the key will be finding a way to implement PHA_Array as a RAM.

    Assuming you are targeting an FPGA, it is likely that you must impose (at least) the following restrictions in order to infer a RAM:

    1. Address a maximum of 2 entries of PHA_Array simultaneously (whether reading, writing or both, at each address).
    2. When reading, the integer must be registered at least 1 time before modifying (+1).

    Currently, the 1st condition is violated when you clear the whole of PHA_Array in parallel during reset. The 2nd condition is violated when you immediately increment the integer in the same cycle that it is read (and written back).

    There is no quick answer to how to fix this, as the best answer depends on your requirements. However, a huge simplification would be if you could guarantee that Add_this_height is never asserted on consecutive clock cycles. If this is the case, then you might try something like this:

    library IEEE;
    use IEEE.STD_LOGIC_1164.ALL;
    use IEEE.NUMERIC_STD.ALL;
    
    entity Proof_Array is
      Port (
        reset                  :   in  std_logic;
        Peak_height_detected_1 :   in  std_logic_vector(9 downto 0);
        Add_this_height        :   in  std_logic;
        S_clk_ADC_15MHz        :   in  std_logic;
        S_Out                  :   out std_logic_vector(31 downto 0));
    end Proof_Array;
    
    architecture Behavioral of Proof_Array is
        type PHA_Array_Type is array (0 to 1023) of integer;
        signal PHA_Array: PHA_Array_Type;
    
        signal Add_this_height_r    : std_logic;
    
        signal RamWrEnA : std_logic;
        signal RamAddrA : unsigned(9 downto 0);
        signal RamOutA  : integer;
    
        signal RamWrEnB : std_logic;
        signal RamAddrB : unsigned(9 downto 0) := (others => '0');
        signal RamOutB  : integer;
    
    begin
    
        PortA_proc : process(S_clk_ADC_15MHz)
        begin
            if rising_edge(S_clk_ADC_15MHz) then
                -- Cycle 1 - Record which address to update
                Add_this_height_r <= Add_this_height;
                if Add_this_height = '1' then
                    RamAddrA <= unsigned(Peak_height_detected_1);
                end if;
    
                -- Cycle 2 - Read from RAM
                RamWrEnA <= Add_this_height_r;
                RamOutA <= PHA_Array(to_integer(RamAddrA));
    
                -- Cycle 3 - Write to RAM (assuming RamAddrA hasn't changed)
                if RamWrEnA = '1' then
                    PHA_Array(to_integer(RamAddrA)) <= RamOutA + 1;
                end if;
            end if;
        end process;
    
        -- Assuming reset is synchronized to S_clk_ADC_15MHz
        RamWrEnB <= reset;
    
        PortB_proc : process(S_clk_ADC_15MHz)
        begin
            if rising_edge(S_clk_ADC_15MHz) then
                -- Always loop this address
                RamAddrB <= RamAddrB + 1;
    
                -- Clear in reset
                if RamWrEnB = '1' then
                    PHA_Array(to_integer(RamAddrB)) <= 0;
                end if;
                -- Read to output
                RamOutB <= PHA_Array(to_integer(RamAddrB));
            end if;
        end process;
    
        S_Out <= std_logic_vector(to_unsigned(RamOutB, S_Out'length));
    
    end Behavioral;
    

    This works by using RAM port "A" to do the Read-Modify-Write part, and RAM port "B" to do the reading out and clearing in reset parts.

    Note again that this assumes Add_this_height is never high on 2 consecutive cycles. Even if this assumption is incorrect, you could try synthesizing this code. If it synthesizes relatively quickly, then that at least implies that inferring a RAM may be a good way forward.