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
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:
assign z = myfunction(a,b,c);
function logic myfunction(input a,b,c);
count=count+1; // this is a side-effect that is not synthesizable
count=count+2; // this is a side-effect that is not synthesizable
The asssign z1= statement would never execute because there are no triggering events on the RHS to cause an evaluation.
assign z1 = myfunction();
always_comb z2 = myfunction();
function logic myfunction();
else z ='bx; // a don't care to prevent a latch
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
that fails because there was never an event to trigger the always @(*) block.
`define PI 3.14159
always @(*) pi = `PI; // DO NOT EVER DO use always_comb pi = `PI; instead