0
\$\begingroup\$

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?

\$\endgroup\$
  • 1
    \$\begingroup\$ Just put the whole lot in the clocked process. Simpler and far less error prone. Why books still teach the spurious 2-process form I can't imagine. \$\endgroup\$ – Brian Drummond Aug 25 '15 at 11:16
3
\$\begingroup\$

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;
\$\endgroup\$
  • \$\begingroup\$ You're right, I do come from a software development background. You have no idea how hard it is for me to grasp these concepts :) Can you name a simple example on my code how to resolve one error? \$\endgroup\$ – idjuradj Aug 24 '15 at 23:25
  • \$\begingroup\$ There are a couple of basic rules you have to follow. 1. anytime you read a signal inside a process, the signal must be in the sensitivity list. 2. In a combinatorial process, all signals must have a defined value under all conditions in that process. 3. Try onot to have multiple if-then-else and when statements in the same process, split it into smalelr process with one simple if-then-else or case statement. 3. The case statement, if not fully cover all the 'cases' must have a "others" section where signals are set, you can also set signals to defaul value outside of case statement. \$\endgroup\$ – FarhadA Aug 25 '15 at 13:11
  • \$\begingroup\$ @FarhadA You said " 1. anytime you read a signal inside a process, the signal must be in the sensitivity list.". What if I want to use that signal as an internal register? I simply want to store a value in it. Do I have to add it to sensitivity list in that case as well? \$\endgroup\$ – idjuradj Aug 25 '15 at 19:13
  • \$\begingroup\$ @MarkU Thanks alot for the detailed reply. However, I still get the same warnings. Even when I added the code you suggested in Others case, I still got the same warnings. I tried adding an else branch in every if inside cases, but that didn't help either. I understand that I have to have an assignment in every possible scenario of the process execution, and obviously I don't have that in my process. What am I missing? \$\endgroup\$ – idjuradj Aug 25 '15 at 19:34
  • \$\begingroup\$ @Nicolas, YES, whenever you READ a signal inside a process, that signal MUST be in your sensitivity list. No exception. Alternative is to create a clocked process where only the clock and the reset (if you have one) should be placed on your sensitivity list). \$\endgroup\$ – FarhadA Aug 26 '15 at 12:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.