SystemVerilog, if-statements order inside an always_comb block - if-statement

I am new to SystemVerilog and I would like to know how multiple assignments to the same signal are handled inside an always_comb block.
I am analyzing an FSM written by someonelse and I don't understand which would be the next state (signal named "ctrl_fsm_ns") if all the if-statements are true. Searching on google, I found out that here blocking assignments are used, so I expect that the last if-statement will decide the next state (so it is like a certain priority is assigned to each if-statement). But what if inside each if-block different signals are asserted? They will be all asserted even if the next state will be the last one, for example?
Here is the piece of code I don't understand.
always_comb
begin
...
unique case (ctrl_fsm_cs)
...
FIRST_FETCH:
begin
is_decoding_o = 1'b0;
// Stall because of IF miss
if ((id_ready_i == 1'b1) )
begin
ctrl_fsm_ns = DECODE;
end
// handle interrupts
if (irq_req_ctrl_i & irq_enable_int) begin
// This assumes that the pipeline is always flushed before
// going to sleep.
ctrl_fsm_ns = IRQ_TAKEN_IF;
halt_if_o = 1'b1;
halt_id_o = 1'b1;
end
if ((debug_req_pending || trigger_match_i) & (~debug_mode_q))
begin
ctrl_fsm_ns = DBG_TAKEN_IF;
halt_if_o = 1'b1;
halt_id_o = 1'b1;
end
end

Your question to the code above is a general programming question and not Verilog-specific. Because there are only blocking assignments in use, the code is entirely procedural.
Since the code isn't using an "if-else-if" sequence, but just "if-if-if", all the "if" conditions will be evaluated IN ORDER, and all assignments will happen IN ORDER, thus the final assignment will win out (as Dave said).
In your comments above you asked about what if (A_expr,B_expr,C_expr) where all true? Then (A,B,C) will all be set to 1.
A_expr=1; B_expr=1; C_expr=1;
if (A_expr) A = 1;
if (B_expr) B = 1;
if (C_expr) C = 1;

For each variable in the always_comb block, the last assignment is the final value. The tool analyzes the procedural flow to make sure every variable that is being assigned has at least one assignment in every possible flow through the code. If there is any possibility that a variable could be read without being written to, that is considered latch behavior and would be illegal for an always_comb block.
You need to look at the code before or after the case statement to see if there are any other assignments to the halt_ variables.
An example based on your comments:
always_comb begin
A = 0; B = 1; C = 2;
if (I) A = X;
if (J) B = Y;
if (K) begin B = Z; C = Z; end
end
That is equivalent to these three continuous assignments:
assign A = I ? X : 0;
assign B = K ? Z : (J ? Y : 1 );
assign C = K ? Z : 2;
Each if statement becomes a multiplexor, and the latter statements have the higher priority.

Related

Will if-else statements nest without brackets?

I want to write something utterly ridiculous that calls for a great depth of conditional nesting. The least disorienting way to write this is to forgo brackets entirely, but I have not been able to find any info on if nesting single-statement if-else guards is legal; the non-nested version causes people enough problems it seems.
Is it valid to write the following? (In both C and C++, please let me know if they differ on this.)
float x = max(abs(min), abs(max));
uint32 count = 0u;
// divides and conquers but, tries to shortcut toward more common values
if (x < 100'000.f)
if (x < 10.f)
count = 1u;
else
if(x < 1'000.f)
if (x < 100.f)
count = 2u;
else
count = 3u;
else
if (x < 10'000.f)
count = 4u;
else
count = 5u;
else
... // covers the IEEE-754 float32 range to ~1.0e+37 (maybe 37 end branches)
--skippable lore--
The underlying puzzle (this is for fun) is that I want to figure out the number of glyphs necessary to display a float's internal representation without rounding/truncation, in constant time. Counting the fractional part's glyph count in constant time was much neater/faster, but unfortunately I wasn't able to figure out any bit-twiddling tricks for the integer part, so I've decided to just brute-force it. Never use math when you can use your fists.
From cppreference.com:
in nested if-statements, the else is associated with the closest if that doesn't have an else
So as long as every if has an else, nesting without brackets works fine. The problem occurs when an else should not be associated with the closest if. For example:
if ( condition1 ) {
if ( condition2 )
DoSomething();
} // <-- This is needed so the else goes with the intended if.
else
DoOtherThing();
A quick scan of your code looks like it's fine.

Bit wise 'AND' an array of registers in Verilog

I have an array of registers/buses and a single result bus defined as follows.
wire [BW-1:0] bus_array[NUM-1:0];
reg [BW-1:0] and_result;
where
parameter BW = 4;
parameter NUM = 8;
I wish to perform a BW-bit AND operation on the elements of the array and assign the result to the register and_result.
I try doing this as follows.
integer l;
generate
genvar m;
for (m=0; m<BW; m=m+1)
begin : BW_LOOP
always # (*)
begin
and_result[m] = 1'b1;
for (l=0; l<NUM; l=l+1)
and_result[m] = and_result[m] & bus_array[l][m];
end
end
endgenerate
However when I simulate this in Modelsim 10.1e, I get the following error.
Error: (vsim-3601) Iteration limit reached at time 2 ns
If I do not use the generate loop, and instead have BW instances of the always # (*) block, the simulation works okay.
I can infer from the error message, that there is a problem with the generate for loop, but I am not able to resolve the problem.
Most likely a bug with ModelSim. Reproducible on EDAplayground with ModelSim10.1d. Works fine with Riviera2014 (After localizing l inside the generate loop). I'm guessing that and_result[m] is somehow in the #(*) sensitivity list, which it shouldn't be.
l needs to be localized or it will be accessed in parallel with the generated always blocks; creating a potential raise condition.
One workaround is to use SystemVerilog and use always_comb instead of always #(*).
A backwarnd compatable solution is to change and_result[m] = and_result[m] & bus_array[l][m]; to if (bus_array[l][m]==1'b0) and_result[m] = 1'b0; which is equivalent code. This keeps and_result[m] only on as a left hand expression so it cannot be in the sensitivity list.
genvar m;
for (m=0; m<BW; m=m+1)
begin : BW_LOOP
integer l; // <== 'l' is local to this generate loop
always # (*)
begin
and_result[m] = 1'b1;
for (l=0; l<NUM; l=l+1) begin
if (bus_array[l][m]==1'b0) begin
and_result[m] = 1'b0;
end
end
end
Working code here

difference between 'when' and 'if' in OpenModelica?

I'm new to OpenModelica and I've a few questions regarding the code of 'BouncingBall.mo' which is distributed with the software as example code.
1) what's the difference between 'when' and 'if'?
2)what's the purpose of variable 'foo' in the code?
3)in line(15) - "when {h <= 0.0 and v <= 0.0,impact}",, shouldn't the expression for 'when' be enough as "{h <= 0.0 and v <= 0.0}" because this becomes TRUE when impact occurs, what's the purpose of impact(to me its redundant here) and what does the comma(,) before impact means?
model BouncingBall
parameter Real e = 0.7 "coefficient of restitution";
parameter Real g = 9.81 "gravity acceleration";
Real h(start = 1) "height of ball";
Real v "velocity of ball";
Boolean flying(start = true) "true, if ball is flying";
Boolean impact;
Real v_new;
Integer foo;
equation
impact = h <= 0.0;
foo = if impact then 1 else 2;
der(v) = if flying then -g else 0;
der(h) = v;
when {h <= 0.0 and v <= 0.0,impact} then
v_new = if edge(impact) then -e * pre(v) else 0;
flying = v_new > 0;
reinit(v, v_new);
end when;
end BouncingBall;
OK, that's quite a few questions. Let me attempt to answer them:
What is the difference between when and if.
The questions inside a when clause are only "active" at the instant that the conditional expressions used in the when clause becomes active. In contrast, equations inside an if statement are true as long as the conditional expression stays true.
What's the purpose of foo?
Probably for visualization. It has no clear impact on the model that I can see.
Why is impact listed in the when clause.
One of the problems you have so-called Zeno systems like this is that it will continue to bounce indefinitely with smaller and smaller intervals. I suspect the impact flag here is meant to indicate when the system has stopped bouncing. This is normally done by checking to make sure that the conditional expression h<=0.0 actually becomes false at some point. Because event detection includes numerical tolerancing, at some point the height of the bounces never gets outside of the tolerance range and you need to detect this or the ball never bounces again and just continues to fall. (it's hard to explain without actually running the simulation and seeing the effect).
What does the , do in the when clause.
Consider the following: when {a, b} then. The thing is, if you want to have a when clause trigger when either a or b become true, you might think you'll write it as when a or b then. But that's not correct because that will only trigger when the first one becomes true. To see this better, consider this code:
a = time>1.0;
b = time>2.0;
when {a, b} then
// Equation set 1
end when;
when a or b then
// Equation set 2
end when;
So equation set 1 will get executed twice here because it will get executed when a becomes true and then again when b becomes true. But equation set 2 will only get executed once when a becomes true. That's because the whole expression a or b only becomes true at one instant.
These are common points of confusion about when. Hopefully these explanations help.

Generate Block Compile Time If-Else Parameterized

I'm looking to be able to parametric some behavioral level Verilog using the generate block. The module is for a re-configurable readout and FIFO block, mainly so we can code this up one and just use a parameter at the top level.
Lets say we have:
always #(posedge write_out_clk or posedge RESETN)
begin
if (RESETN)
SENSE_ADDR <= 0;
else if (enb[0] == 1)
SENSE_ADDR <= 1; // for example but may be some other wire/bus etc
else if (enb[1] == 2)
SENSE_ADDR <= 1; // for example but may be some other wire/bus etc
else
SENSE_ADDR <= SENSE_ADDR;
end
end
This is behavioral so the specifics of implementation are left to the compiler with user given timing constraints etc. This works for 'n' else-if statements within the block if I hard code them, currently synthesis and simulation are both working for 16 statements.
My question however is how to parameterise this using generate? Clearly if 'n=8' its not too much of a big deal to hard code it. What if 'n=64' or 'n=128' etc. Seems a shame to hard code it if the rest of the module is fully parameterized using the generate for 'n'...
I have tried doing something like:
genvar elseif_generate;
generate
for (elseif_generate=0; elseif_generate<FIFO_SUB_BLOCKS; elseif_generate=elseif_generate+1)
begin: elseif_generate_logic
always #(posedge write_out_clk or posedge RESETN)
begin
if (RESETN)
SENSE_ADDR <= 0;
else if (enb[elseif_generate] == 1)
SENSE_ADDR <= some_wire[elseif_generate];
else
SENSE_ADDR <= SENSE_ADDR;
end
end
endgenerate
This however leads to Multi-source errors for the output wire 'SENSE_ADDR'. This leads me to the further question. Clearly a generate block is not suitable here but how would I go about implementing parameterised code replication for this block? Basically I want the functionality of the behavioral, hard coded if-else always block in a parameterised form...
Does this serve your needs? No generate required.
module mux #(
parameter WIDTH = 5,
parameter NUM = 2,
parameter NUMLG = $clog2(NUM)
) (
input [NUMLG -1:0] sel,
input [WIDTH - 1:0] in [0:NUM-1],
output [WIDTH - 1:0] out
);
assign out = in[sel];
endmodule
If your simulator doesn't support SystemVerilog that well you'll have to modify this to blow out the input array but the concept is the same.
You don not need a generate block. Add a combination always block to calculate next_SENSE_ADDR that will be flopped to SENSE_ADDR.
always #(posedge write_out_clk or posedge RESETN)
begin
if (RESETN)
SENSE_ADDR <= 0;
else
SENSE_ADDR <= next_SENSE_ADDR;
end
integer idx;
always #* begin // #(SENSE_ADDR or enb or some_wire)
next_SENSE_ADDR = SENSE_ADDR; // default, value if enb is all 0
// count down because lsb has higher priority
for ( idx=FIFO_SUB_BLOCKS-1; idx>=0; idx-- ) begin
if ( enb[idx] )
next_SENSE_ADDR = some_wire[idx];
end
end

Effect of using a comma instead of a semi-colon in C and C++

I've noticed on a number of occasions when refactoring various pieces of C and C++ code that a comma is used rather than a semi-colon to seperate statements. Something like this;
int a = 0, b = 0;
a = 5, b = 5;
Where I would have expected
int a = 0, b = 0;
a = 5; b = 5;
I know that C and C++ allow use of commas to seperate statements (notably loop headers), but what is the difference if any between these two pieces of code? My guess is that the comma has been left in as the result of cut & pasting, but is it a bug and does it effect execution?
It doesn't make a difference in the code you posted. In general, the comma separates expressions just like a semicolon, however, if you take the whole as an expression, then the comma operator means that the expression evaluates to the last argument.
Here's an example:
b = (3, 5);
Will evaluate 3, then 5 and assign the latter to b. So b = 5. Note that the brackets are important here:
b = 3, 5;
Will evaluate b = 3, then 5 and the result of the whole expression is 5, nevertheless b == 3.
The comma operator is especially helpful in for-loops when your iterator code is not a simple i++, but you need to do multiple commands. In that case a semicolon doesn't work well with the for-loop syntax.
The comma is a operator that returns a value which is always the 2nd (right) argument while a semicolon just ends statements. That allows the comma operator to be used inside other statements or to concatenate multiple statements to appear as one.
Here the function f(x) gets called and then x > y is evaluated for the if statement.
if( y = f(x), x > y )
An example when it's used just to avoid a the need for block
if( ... )
x = 2, y = 3;
if( ... ) {
x = 2;
y = 3;
}
The comma operator evaluates all operands from left to right, and the result is the value of the last operand.
It is mostly useful in for-loops if you want to do multiple actions in the "increment" part, e.g (reversing a string)
for (int lower = 0, upper = s.size() - 1; lower < upper; ++lower, --upper)
std::swap(s[lower], s[upper]);
Another example, where it might be an option (finding all occurrences in a string):
#include <string>
#include <iostream>
int main()
{
std::string s("abracadabra");
size_t search_position = 0;
size_t position = 0;
while (position = s.find('a', search_position), position != std::string::npos) {
std::cout << position << '\n';
search_position = position + 1;
}
}
In particular, logical and cannot be used for this condition, since both zero and non-zero can mean that the character was found in the string. With comma, on the other hand, position = s.find() is called each time when the condition is evaluated, but the result of this part of the condition is just ignored.
Naturally there are other ways to write the loop:
while ((position = s.find('a', search_position)) != std::string::npos)
or just
while (true) {
position = s.find('a', search_position);
if (position == std::string::npos)
break;
...
}
As Frank mentioned, how the comma operator is used in your example doesn't cause a bug. The comma operator can be confusing for several reasons:
it's not seen too often because it's only necessary in some special situations
there are several other syntactic uses of the comma that may look like a comma operator - but they aren't (the commas used to separate function parameters/arguments, the commas used to separate variable declarations or initializers)
Since it's confusing and often unnecessary, the comma operator should be avoided except for some very specific situations:
it can be useful to perform multiple operation in one or more of a for statement's controlling expressions
it can be used in preprocessor macros to evaluate more than one expression in a single statement. This is usually done to allow a macros to do more than one thing and still be a a single expression so the macro will 'fit' in places that only allow an expression.
The comma operator is a hackish operator pretty much by definition - it's to hack in 2 things where only one is allowed. It's almost always ugly, but sometimes that's all you've got. And that's the only time you should use it - if you have another option, don't use the comma operator.
Off the top of my head I can't think of too many other reasons to use the operator, since you can get a similar effect by evaluating the expressions in separate statements in most other situations (though I'm sure that someone will comment on a another use that I've overlooked).
One usage would be in code golfing:
if (x == 1) y = 2, z = 3;
if (x == 1) { y = 2; z = 3; }
The first line is shorter, but that looks too confusing to use in regular development.