Your always_comb blocks is not combinatorial - if a != b, and b != c, then there is no assignment to z and you have a latch. Your second if statement needs an else clause.
In any case, the conditional ?: operator can be nested:
assign z = (a==b) ? a : (b==c) ? b : z;
That z at the end represents the missing else clause.
Uhm, no? It's in the rough same area of things that look like similar stuff, but I would not say they are identical.
Even easier ... if you want to do it in verilog, and are a bit miffed that plain old verilog doesn't have "always_comb" ... well you can always use "always". So in your case:
Code Verilog - [expand]
1
2
3
4
5
6
7
8
always@*//always, just like always_comb functionally speaking is somewhere in the same galaxy as assign. sometimes.beginif(a==b)
z=a;elseif(b==c)
z=b;end
Incidentally, what is z supposed to be when a!=b and b!=c ? Your code snippet doesn't have much to say about that situation...
- - - Updated - - -
Heh, this seems like a popular minute for replies! XD
Updated update: awwww, the "Updated" messed my minute. That makes me very sad. ;(
mrflibble: Could you briefly talk about why always_comb and assign are different? because when I read some verilog beginner's book, it said that are doing the same things.
If you want your code to be synthesizable, you cannot combine combinatorial and sequential logic like this in a single assign statement. You will need to explain your desired functionality without using any Verilog syntax first so we can suggest the best way to code what you want to achieve.
If you don't care if your code is synthesizable, you can assign the output of a function call
Code:
assign z = myfunction(a,b,c);
function logic myfunction(input a,b,c);
if(a==b)
begin
z=a;
count=count+1; // this is a side-effect that is not synthesizable
end
else
if (b==c)
begin
z=b;
count=count+2; // this is a side-effect that is not synthesizable
end
endfunction
The biggest difference between always_comb and an assign statement is with the how the simulator deals with the semantics of function calls. An assignment statement only looks for events on the operands that appear on the RHS of the assignment, while always_comb expands functions in-line and looks for any change of any operand that appears inside the function. For example suppose I re-wrote the function to directly reference a,b,c instead of passing them as arguments to the function:
Code:
assign z1 = myfunction();
always_comb z2 = myfunction();
function logic myfunction();
if(a==b)
z=a;
else
if (b==c)
z=b;
else z ='bx; // a don't care to prevent a latch
endfunction
The asssign z1= statement would never execute because there are no triggering events on the RHS to cause an evaluation.
The always_comb z2= block executes at time 0, and when there is a change on any operand that is referenced within the block.
mrfibble, I recommend NEVER TO USE always @(*) because it does not guarantee execution at time 0. I have Seen code like
Code:
real pi;
`define PI 3.14159
always @(*) pi = `PI; // DO NOT EVER DO use always_comb pi = `PI; instead
that fails because there was never an event to trigger the always @(*) block.
mrflibble: Could you briefly talk about why always_comb and assign are different? because when I read some verilog beginner's book, it said that are doing the same things.
I readily agree with that recommendation. I was just going with the OP's flow of it being verilog-2001 as opposed to system verilog.
No always_comb in the old school verilog, hence the always @(*) remark. But when you have the luxury of tools that do system verilog, then I'd say go for always_comb, always_ff etc.
The pointer to make sure you know what happens at time 0 in your simulation is a good one to remind oneself of...