0
\$\begingroup\$

Is it a valid and synthesizeable VHDL code?

case IR(10 downto 7) is -- RD
    when "0000" => R0 <= RTA;
    when "0001" => R1 <= RTA;
    when "0010" => R2 <= RTA;
    when "0011" => R3 <= RTA;
    when "0100" => R4 <= RTA;
    when "0101" => R5 <= RTA;
    when "0110" => R6 <= RTA;
    when "0111" => R7 <= RTA;
    when "1000" => R8 <= RTA;
    when "1001" => R9 <= RTA;
    when "1010" => R10 <= RTA;
    when "1011" => R11 <= RTA;
    when "1100" => R12 <= RTA;
    when "1101" => R13 <= RTA;
    when "1110" => R14 <= RTA;
    when "1111" => R15 <= RTA;
    when others => null ;
end case;

As you see in each case the output signal is different: R0, R1, R2, etc. I thought maybe I have to put all the outputs in each case; Something like this:

case IR(10 downto 7) is -- RD
    when "0000" => 
       R0 <= RTA;
       R1 <= 0;  -- The problem here is that I don't want R1 to be 0
                 --   but to retain its previous value
       R2 <= 0;
       R3 <= 0;
       R4 <= 0;
       R5 <= 0;
       R6 <= 0;
       R7 <= 0;
       R8 <= 0;
       R9 <= 0;
       R10 <= 0;
       R11 <= 0;
       R12 <= 0;
       R13 <= 0;
       R14 <= 0;
       R15 <= 0;
    when "0001" => 
       R0 <= 0;
       R1 <= RTA;
       R2 <= 0;
       R3 <= 0;
       R4 <= 0;
       R5 <= 0;
       R6 <= 0;
       R7 <= 0;
       R8 <= 0;
       R9 <= 0;
       R10 <= 0;
       R11 <= 0;
       R12 <= 0;
       R13 <= 0;
       R14 <= 0;
       R15 <= 0;
    .
    .
    .
    when others => null ;
end case;

If I don't have all the outputs (R0 to R15) into each case the VHDL compiler gives me a warning: "Found 1-bit latch for signal . Latches may be generated from incomplete case or if statements. We do not recommend the use of latches in FPGA/CPLD designs, as they may lead to timing problems."

I need to get rid of this warning.

\$\endgroup\$
1
\$\begingroup\$

Verilog and VHDL are hardware description languages, but they do look similar to procedural programming languages. This can sometimes lead to code that is technically valid but not synthesize-able.

In your first example code, each output not explicitly specified with a new value, implicitly retains its previous value (because that's what would happen in a procedural programming language). That is the "implicit latch" that the synthesis tools are warning about. This HDL code might be technically valid, but may not be synthesize-able (or maybe not in the way that is intended). The problem is that the synthesis tool can't do what you want without also synthesizing the actual memory to store the values, and it's not clear that is what you want. Apparently you didn't tell it to create any memory to store those values.

Your second example code explicitly determines the value of each output in each case, so the synthesis tool understands exactly what you want. In your second example, only one output gets the RTA value, and the rest of the outputs are 0. This is valid and synthesize-able, however you mention in the comments that this isn't really what you want either, you actually want to update one register while retaining the values of the other registers.

To write HDL code that updates the value of a selected register, you need to declare the actual memory elements. I'm not a VHDL guy, but in Verilog I'd maybe write something like this:

// declare R0..R15 as register storage (memory), not just signal wires
reg[7:10] R0;
reg[7:10] R1;
// etc...
reg[7:10] R15;
// could be written more efficiently as a register file instead of individual registers

// update a register selected by IR[10:7] with data RTA
always @(posedge clock)
begin
    case(IR[10:7])
    4'b0000: 
        R0 <= RTA;
        break;
    4'b0001: 
        R1 <= RTA;
        break;
    // etc.
    4'b1111: 
        R15 <= RTA;
        break;
    endcase
    // 
end
\$\endgroup\$
  • \$\begingroup\$ Ok so basically it is safe to ignore the warning. I 'll accept your answer, thanks. \$\endgroup\$ – Ehsan Nov 22 '16 at 5:14
  • \$\begingroup\$ No, it is not safe to ignore the "Found 1-bit latch for signal", since I don't think your intention is to make a latch in your FPGA. \$\endgroup\$ – Morten Zilmer Nov 22 '16 at 6:58
  • \$\begingroup\$ I declared the R0 to R15 as memory registers, isn't that enough? \$\endgroup\$ – Ehsan Dec 4 '16 at 6:42
1
\$\begingroup\$

The case itself adheres to VHDL syntax, and in general synthesis tools handles case.

The warning is related to general coding style. If a process is used to make combinatorial logic, then all the signals driven from a process must always be assigned in order to avoid latches, but my guess without seeing the rest of your code, is that it is not the case. A good coding style (when feasible) is to assign all the signals in the beginning of the process, like:

process (IR, RTA, ...) is
begin
    R0 <= ...;
    R1 <= ...;
    ...
    case ...
end;

So to avoid the warning and the latches, ensure that all the signals driven from a combinatorial process are assigned.

For example this code will intentionally make a latch, since q is held if en = '0', and only updated if en = '1':

process (en, d) is
begin
    if en = '1' then
        q <= d;
    end if;
end process;

For sequential logic there is not the same problem, since flip-flops can just hold they state if they are not updated.

\$\endgroup\$
1
\$\begingroup\$

This CASE statement is valid VHDL. A normal use of it would be embedded in a if rising_edge(clk) then statement, in which case it won't generate a latch but a clocked register.

Then the first form updates one register on a clock edge, preserving the value of all the others.

The second form updates one register, clearing all the others (which is rarely what you want to do). It can be greatly simplified by moving a default assignment before the CASE statement...

if rising_edge(clk) then
   R0 <= 0;
   R1 <= 0;
   -- etc
   case () is
   when 0 => R0 <= RTA;
   -- etc
   end case;
end if;

Here the "last assignment wins" rule in synchronous processes takes care of the default actions, overridisng only the one you want.


An aside: any time you see large regular CASE statements like this, they are probably ripe for a huge simplification - consider the following, which eliminates the CASE entirely.

type Register is natural range 0 to 255;
type Register_File is array (0 to 15) of Register;
signal R : Register_File;
-- optional if you need teh original register names somewhere...
alias R0 : Register is R(0); -- etc for each register

...

    if rising_edge(clk) then
       -- optional second case
       -- R <= (others => 0);  
       R(to_integer(unsigned(IR(10 downto 7)))) <= RTA;
    end if;

If the CASE statements are irregular, that simplification isn't so easy.

\$\endgroup\$

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.