Help with resolving warning “inferring latch(es) for signal or variable ”..“, which holds its previous value in one or more paths through the process”

intel-fpgaquartus-iivhdl

Below is the code for my branch unit implementation. This unit calculates the jump destination address and writes it into the PC register.

There are a few different types of jumps, etc, standard story.

library IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.NUMERIC_STD.ALL;
USE work.defPaket.all;

entity BR_UNIT is
Port ( 
    CLK                 : in  STD_LOGIC; -- clock
    RST                 :       in  STD_LOGIC;

    N                       : in  STD_LOGIC; -- negative
    Z                       : in  STD_LOGIC; -- zero
    C                       : in  STD_LOGIC; -- carry
    V                       : in  STD_LOGIC; -- overflow

    flushfifo           : out STD_LOGIC;
    pcOUT                   : out STD_LOGIC_VECTOR (31 downto 0);
    pcWrEn              : out STD_LOGIC;

    in1                 : in STD_LOGIC_VECTOR (31 downto 0); --input1
    in2                 : in STD_LOGIC_VECTOR (31 downto 0); --input1

    validOut                : out STD_LOGIC; --output
    wr_reg              : out STD_LOGIC;
    regOut              : out STD_LOGIC_VECTOR (4 downto 0);
    dataVal             : out STD_LOGIC_VECTOR (31 downto 0)
);

end BR_UNIT;

architecture Behavioral of BR_UNIT is

signal opc              : STD_LOGIC_VECTOR (4 downto 0);
signal newpc            : STD_LOGIC_VECTOR (31 downto 0);
signal offset           : STD_LOGIC_VECTOR (31 downto 0);

signal validOut_t       : STD_LOGIC;
signal wr_reg_t     : STD_LOGIC;
signal regOut_t     : STD_LOGIC_VECTOR (4 downto 0);
signal dataVal_t        : STD_LOGIC_VECTOR (31 downto 0);
signal pcOUT_t          : STD_LOGIC_VECTOR (31 downto 0);
signal pcWrEn_t     : STD_LOGIC;
signal flushfifo_t  : STD_LOGIC;

begin

clk_part : process (CLK)

begin

if (CLK'event and CLK = '1') then
    validOut <= validOut_t;
    wr_reg <= wr_reg_t;
    regOut <= regOut_t;
    dataVal <= dataVal_t;
    pcOUT <= pcOUT_t;
    pcWrEn <= pcWrEn_t;
    flushfifo <= flushfifo_t;
end if;

end process;

comb_part : process (in1, in2, N, Z, C, V)
    variable temp : signed(31 downto 0);

    begin

    if(
        (in1(31 downto 27) = OPC_BEQ) or
        (in1(31 downto 27) = OPC_BGT) or
        (in1(31 downto 27) = OPC_BHI) or
        (in1(31 downto 27) = OPC_BAL) or
        (in1(31 downto 27) = OPC_BLAL)
    ) then

        opc <= in1(31 downto 27);

    elsif(
        (in2(31 downto 27) = OPC_BEQ) or
        (in2(31 downto 27) = OPC_BGT) or
        (in2(31 downto 27) = OPC_BHI) or
        (in2(31 downto 27) = OPC_BAL) or
        (in2(31 downto 27) = OPC_BLAL)
    ) then

        opc <= in2(31 downto 27);

    end if;

    offset <= std_logic_vector(resize(signed(in1(26 downto 0)), 32));
    temp := signed(offset) + signed(in1(8 downto 1)) + 1;
    newpc <= std_logic_vector(signed(temp));

    regOut_t <= "00000";
    validOut_t <= '1';

        case opc is

            when OPC_BEQ =>
                if (Z = '1') then
                    flushfifo_t <= '1';
                    pcOUT_t <= newPC;
                    pcWrEn_t <= '1';
                end if;

            when OPC_BGT =>
                if (((N xor V) or Z) = '0') then
                    flushfifo_t <= '1';
                    pcOUT_t <= newPC;
                    pcWrEn_t <= '1';
                end if;

            when OPC_BHI =>
                if ((C or Z) = '0') then
                    flushfifo_t <= '1';
                    pcOUT_t <= newPC;
                    pcWrEn_t <= '1';
                end if;

            when OPC_BAL =>
                    flushfifo_t <= '1';
                    pcOUT_t <= newPC;
                    pcWrEn_t <= '1';

            when OPC_BLAL =>
                    flushfifo_t <= '1';
                    pcOUT_t <= newPC;
                    pcWrEn_t <= '1';

                    regOut_t <= "00000";
                    dataVal_t <= newpc; 
                    wr_reg_t <= '1';

            when OTHERS =>
        end case;

end process;

end Behavioral;

Quartus altera throws the following warnings:

Warning (10492): VHDL Process Statement warning at IDEXWBBranchUnit.vhd(94): signal "offset" is read inside the Process Statement but isn't in the Process Statement's sensitivity list

Warning (10492): VHDL Process Statement warning at IDEXWBBranchUnit.vhd(100): signal "opc" is read inside the Process Statement but isn't in the Process Statement's sensitivity list

Warning (10492): VHDL Process Statement warning at IDEXWBBranchUnit.vhd(105): signal "newpc" is read inside the Process Statement but isn't in the Process Statement's sensitivity list

Warning (10492): VHDL Process Statement warning at IDEXWBBranchUnit.vhd(112): signal "newpc" is read inside the Process Statement but isn't in the Process Statement's sensitivity list

Warning (10492): VHDL Process Statement warning at IDEXWBBranchUnit.vhd(119): signal "newpc" is read inside the Process Statement but isn't in the Process Statement's sensitivity list

Warning (10492): VHDL Process Statement warning at IDEXWBBranchUnit.vhd(125): signal "newpc" is read inside the Process Statement but isn't in the Process Statement's sensitivity list

Warning (10492): VHDL Process Statement warning at IDEXWBBranchUnit.vhd(130): signal "newpc" is read inside the Process Statement but isn't in the Process Statement's sensitivity list

Warning (10492): VHDL Process Statement warning at IDEXWBBranchUnit.vhd(134): signal "newpc" is read inside the Process Statement but isn't in the Process Statement's sensitivity list

Warning (10631): VHDL Process Statement warning at IDEXWBBranchUnit.vhd(66): inferring latch(es) for signal or variable "opc", which holds its previous value in one or more paths through the process

Warning (10631): VHDL Process Statement warning at IDEXWBBranchUnit.vhd(66): inferring latch(es) for signal or variable "flushfifo_t", which holds its previous value in one or more paths through the process

Warning (10631): VHDL Process Statement warning at IDEXWBBranchUnit.vhd(66): inferring latch(es) for signal or variable "pcOUT_t", which holds its previous value in one or more paths through the process

Warning (10631): VHDL Process Statement warning at IDEXWBBranchUnit.vhd(66): inferring latch(es) for signal or variable "pcWrEn_t", which holds its previous value in one or more paths through the process

Warning (10631): VHDL Process Statement warning at IDEXWBBranchUnit.vhd(66): inferring latch(es) for signal or variable "dataVal_t", which holds its previous value in one or more paths through the process

Warning (10631): VHDL Process Statement warning at IDEXWBBranchUnit.vhd(66): inferring latch(es) for signal or variable "wr_reg_t", which holds its previous value in one or more paths through the process

Regarding these warnings about signals not being in the sensitivity list, how do I resolve that? Should I skip using them whenever possible or use variables where not possible?

The big and the main question is: what do these errors mean:

Warning (10631): VHDL Process Statement warning at IDEXWBBranchUnit.vhd(66): inferring latch(es) for signal or variable "opc", which holds its previous value in one or more paths through the process

What do they mean and what are your suggestions on how to resolve them?

Best Answer

I'm guessing that like me, you probably come from a software development background and are now learning HDL.

The when others case is empty; that's where you are implicity making all the latches. You clear this warning by explicitly setting the output's next value to its previous value, like x <= x;. Remember this is a Hardware Description Language, not a procedural computer programming language. So you have to think in terms of what actual hardware you expect each module to implement.

As a general rule, when you have a case statement, each clause (i.e. each "execution path" though that's the wrong terminology) -- should define the value of each of the statement's output ports, even if there is no change intended. There are certain code patterns that HDL synthesis tools recognize, and for best results you should try to stick with those forms whenever possible.


Response to the comment:

There's two kinds of warning mesasges here.

Warning # 10492 seems to indicate that an input signal is missing from the sensitivity list.

Warning (10492): VHDL Process Statement warning at IDEXWBBranchUnit.vhd(105): signal "newpc" is read inside the Process Statement but isn't in the Process Statement's sensitivity list

In the delcaration

comb_part : process (in1, in2, N, Z, C, V)

the sensitivity list only declares in1, in2, N, Z, C, V as the available input signals. In terms of hardware, this is like declaring that comb_part is implemented with some hardware block that has these six inputs -- and then oh by the way, surprise, here's this other signal called offset, which looks like it was meant to be another input.

offset <= std_logic_vector(resize(signed(in1(26 downto 0)), 32));

So because this is a non-blocking assignment statement, offset must be some kind of signal, but is it an internal register or an output? The HDL compiler can't tell of that's what was intended, thus the error message.

Recommended fix is that you need to review your design and determine whether you need to add those inputs to the sensitivity list.

Warning # 10631 seems to indicate that an output signal has an inferred latch.

Warning (10631): VHDL Process Statement warning at IDEXWBBranchUnit.vhd(66): inferring latch(es) for signal or variable "flushfifo_t", which holds its previous value in one or more paths through the process

In software it's assumed that variables hold their value until explicitly changed, but in HDL synthesis that requires a latch or a flip-flop. When you have an HDL module that describes code in terms of "behavioral" statements like if/else, or swtich/case, and there is at least one non-blocking assignment to a signal, then every "execution path" should explicity make a non-blocking assignment to that signal.

    case opc is

        when OPC_BEQ =>
            if (Z = '1') then
                flushfifo_t <= '1';
                pcOUT_t <= newPC;
                pcWrEn_t <= '1';
            end if;
        -- etc...
        when OPC_BLAL =>
                flushfifo_t <= '1';
                pcOUT_t <= newPC;
                pcWrEn_t <= '1';
                regOut_t <= "00000";
                dataVal_t <= newpc; 
                wr_reg_t <= '1';
        when OTHERS =>
                -- [MarkU] here's the problem, missing non-blocking assignments should go here
                flushfifo_t <= flushfifo_t;
                pcOUT_t <= pcOUT;
                pcWrEn_t <=pcWrEn_t;
                -- [MarkU] and so on for all the non-blocking assignments that are unchanged in this case
    end case;
Related Topic