First, note that not all Verilog designs are synthesizable. Usually, only a very specific subset of constructs can be used in a design that is to be realized in hardware.
One important restriction that pops up is that every reg
variable can only be assigned to in at most one always
statement. In other words, reg
s have affinity to always
blocks.
The following types of always
blocks can generally be used.
always @(*) begin
// combinational
end
always @(posedge clk) begin
// sequential
end
In the former case, the *
indicates that the block should be executed whenever any signal used in the block changes or, equivalently, that the block should be executed continuously. Therefore, reg
s that have affinity to combinational always
blocks are implemented as signals computed from other signals using combinational logic, i.e. gates.
Registers that have affinity to always
blocks of the latter type, on the other hand, are outputs of D flip-flops that are clocked on the rising edge of clk
(falling edge if negedge
is used). Inputs to the flip-flops are, again, computed with combinational logic from other signals.
Consider the following, somewhat contrived example.
reg out, out_n;
always @(*) begin
out_n = !out;
end
always @(posedge clk) begin
out <= !out;
end
Here, out_n
is associated with the first always
block, out
with the second. out_n
will be implemented with a single NOT gate that will drive out_n
and be driven from out
(note that it is a pure combinational logic). On the other hand, out
will be driven by a flip-flop clocked from clk
. The input to the flip-flop will again be computed by a NOT gate from out
(which is driven by the aforementioned flip-flop). Optimizing synthesizers will combine the two NOT gates and use one NOT gate and one flip-flop.
Depending on the hardware you have available, other types of constructs can be used. For example, if the flip-flops have asynchronous resets, the following construct is also synthesizable.
always @(posedge clk or posedge rst) begin
if (rst)
// reset
else
// sequential
end
I'm sure there is some way to bind in a C/C++ compile time callback. However, as long as your supports generate
blocks (introduced in IEEE Std 1364-2001), then you can do something like the following:
generate
if (CONDITION > MAX_ALLOWED /* your condition check */ ) begin
illegal_parameter_condition_triggered_will_instantiate_an non_existing_module();
end
endgenerate
If the condition is true, then the compiler will give an error because there is a request for something that doesn't exist. If the condition is false, then the operation is skipped. The only requirement is the code for the illegal condition follows legal Verilog syntax and the illegal condition will never accidentally become valid (hence the long and verbose non-existing module name).
If your simulator and synthesis tools support IEEE Std 1800-2009 (SystemVerilog revision released in 2009) or newer revision, then you can use $error()
and give a more meaningful message to go with the error. I'm not sure if any venders has implemented this feature yet. It should become the preferred method once most venders implemented, therefore I will give an example:
generate
if (CONDITION > MAX_ALLOWED /* your condition check */ ) begin
$error("%m ** Illegal Condition ** CONDITION(%d) > MAX_ALLOWED(%d)", CONDITION, MAX_ALLOWED);
end
endgenerate
Best Answer
You can use the conditional operator
condition ? true_expression : false_expression
as long as everything within the expression is a parameter or literal constant.You can also use functions to define parameters, as long as all the function inputs are parameters or constants as well.