Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Verilog/SV: can assign + ternary produce latches?

Status
Not open for further replies.

pbernardi

Full Member level 2
Joined
Nov 21, 2013
Messages
149
Helped
29
Reputation
58
Reaction score
30
Trophy points
1,308
Activity points
2,867
Hello All,

Looking how a latch can be generated in Verilog/SV, normally the following case is cited:

- use of always@(*) where not all "reg" are updated (normally in cases where you have an "if" condition without a "else" condition when making combinational logic)

However, I have the feeling that the same condition can be achieved when using assign and ternary operator (?:), for example:

(note: code generated by head, might be inaccurate)


Code Verilog - [expand]
1
2
3
4
5
6
7
8
reg [7:0] a;
 
always@(*) 
begin
  if (res) a = 8'h00;
  else if (cond1) a = op1;
  else if (cond2) a = op2;
end



generates a latch, because there are conditions where "a" is not updated. This is equivalent of:


Code Verilog - [expand]
1
2
3
4
5
wire [7:0] a;
 
assign a = res ? 8'h00 : 
           cond1 ? op1 : 
           cond2 ? op2 : a;



But it seems the first one is always cited when generating latches and second one is never cited. Also, the tooling I use at the moment (Vivado 2018.3) does not detect latches in the second case.

I am missing something, or this is a case not covered normally, in a way even some (few? most? all?) tools cannot detect?
 

Yes, both codes are exactly equivalent.

Why do you need latch detection for the concurrent code, the latch condition has to be written explicitly on the R.H.S., hence it's quite obvious.
 

But it seems the first one is always cited when generating latches and second one is never cited. ?

you have to realise they are very different. in the assign case, a is explicitly assigned to itself. this is not the case in the procedural assignments... and that is why students tend to overlook it.
 

Thanks for the answers.

In fact, I had the idea that if I avoid using always@(*), I would avoid latches - mostly because the other case is never talked about. But now I see this is not always the case.

Also it bugs me that in some cases, I make a similar replacement from case 1 (always@(*)) to case 2 (assign) in my code, and Vivado stops generating latches - it does not show the warning during synthesis and does not show the latches in the build report. But I got some cases where the latch is correctly detected, so this bug (feature?) is not always consistent.
 

This is one of the reason SystemVerilog has always_comb, always_latch, always_ff - to show and check your intent
 
Also it bugs me that in some cases, I make a similar replacement from case 1 (always@(*)) to case 2 (assign) in my code, and Vivado stops generating latches - it does not show the warning during synthesis and does not show the latches in the build report. But I got some cases where the latch is correctly detected, so this bug (feature?) is not always consistent.
This is because Vivado and previously ISE weren't always that great at language compliance. Over the years I'd seen all kinds of strange behaviors.

My recommendation is to only write code in specific proven ways that always synthesize correctly and don't diverge from that unless you've proven that a different coding style works well across multiple vendors tools. I also avoid using always@(*) a lot and anytime I use any always statement with an if statement I will write the if like this:
Code:
if () begin
end else if () begin
end else
end
and then fill in the rest of the code, makes it less likely you will forget to cover all branches.
 

More recently, like within the last 5-10 years, this style has started gaining traction. at least online.
Code:
always@(*) begin
  a = 0; // default.  might come from some registered version of "a" like "current_a" if desired.  or some input.  or some constant
  if (something) begin
    a = b;
  end else if (somethingelse) begin
    a = c;
  end
end

This style improves readability and avoids latches. Especially for always@(*) blocks with lots of outputs/cases.
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top