Lint is unable to catch RHS and LSH width mismatch - verilog

Below piece of logic is doing 2^(3+x), where x is 2 bit value and can have max 2'b11, according to the below logic, RHS will be 1 << 6, which is 7'b1000000. MSB will be discarded as LHS is of 6 bits.
Checked this code in Spyglass Lint, VCS compile elab, Synthesis results etc, couldn't find any violation. Is there a tool that can find mistakes like below?
module module_test (
input wire [1:0] x,
output wire [5:0] y
);
assign y = 6’d1 << (3 + x);
endmodule

The problem is discarding some or all the bits of a value when shifting is a perfectly valid thing to want to do. A static linting tool checker is not designed to catch all possible functional bugs.
If you had an assertion that y must always have a one-hot value, then a formal property checker can statically determine that the result could be 0 and generate a violation. Assertions are what you use to capture design intent, and either a static formal tool or dynamic simulation tool can catch differences between intent and what got implemented in RTL.

Related

How to assign "all the last bits" automatically in Verilog

Consider this
reg [5:0]assign_me;
reg [11:0]source_of_data;
assign_me <= source_of_data[5:0];
where assign_me always gets the least significant bits of source_of_data. Here the 5 is hardcoded in the last line in the sense that if for some reason the definition of assign_me changes to reg [6:0]assign_me I will have to change the last line. Is there any way to avoid this? Like for example in a pythonic notation something like assign_me <= source_of_data[:0]?
You could use:
assign_me <= source_of_data;
Verilog will assign the LSB's. But, you might get warnings about width mismatch.
A cleaner way is to use a parameter:
parameter WIDTH = 6;
reg [WIDTH-1:0]assign_me;
reg [11:0]source_of_data;
assign_me <= source_of_data[WIDTH-1:0];
When it comes to integral (packed) arrays, Verilog is loosely typed. Verilog will right justify to align LSBs, then make the assignment padding or truncating the MSB. You do not need to select a specific set of bits unless you need to mask bits on either end. Some tools will generate size mismatch warnings, especially around port connections, but the language does not require it.
One thing to be careful of is that selecting bits of a single is always unsigned regardless of the sightedness of the signal as a whole.

Accessing register values in verilog

I initialize a register
reg[1:0] yreg;
and manipulate it a bit, i.e., value from prev. iteration of program is shifted to 1 spot when I add in the new value in the 0 spot
yreg = SIGNAL; //here SIGNAL is an input to the program
And then I want to access the values at the 0 and 1 spots in the register later for a calculation. How can I do this? My initial reaction was yreg[0] and yreg[1] (I normally program in python =) but this is producing an error (line 35 is the line of code that has yreg[0] and yreg[1] in it):
ERROR:HDLCompiler:806 - "/home/ise/FPGA/trapezoid/trapverilog.v" Line 35: Syntax error near "[".
My assumption when I saw this was that it's not the right syntax to use the brackets to access a certain index of the register. How do you properly access the information in an index of a register? I'm having trouble finding information on this.
Sorry for the probably ridiculous question, this is my first time ever using verilog or FPGAs in general.
Full Code
module trapverilog(
input CLK,
input SIGNAL,
input x,
output OUT
);
reg[1:0] yreg;
float sum = 0;
always #(posedge CLK)
begin
yreg = SIGNAL; //should shift automatically...?
sum = ((reg[0] + reg[1])*x/2) + sum; //this is effectively trapezoidal integration
OUT = sum;
end
endmodule
You have a fundamental misunderstanding of how Verilog signals work.
By default, all Verilog signals are single bits. For example, in your code, SIGNAL, x, and out are all one bit wide. They cannot store a number (other than 0 or 1).
Specifying a width when you define a signal (like reg [1:0] yreg) controls how many bits are used to represent that signal. For instance, yreg is a two-bit signal. This does not mean that it "shifts automatically"; it just means that the signal is two bits wide, allowing it to be used to represent numbers from 0 to 3 (among other things).
I would strongly advise that you work through a course in digital electronics design. Verilog programming is very different from procedural programming languages (such as Python), and you will have a hard time making sense of it without a solid understanding of what you are actually building here.
Apparently as per this answer using brackets to get a certain index of a register is correct. I just forgot to call the variable properly - I was calling reg[0] instead of yreg[0]. Changing this fixed the error.

Default statement in SystemVerilog Case

I'm trying to understand following scenario:
typedef enum logic [2:0] {
ONE, TWO, THREE, FOUR, FIVE
} enum_t;
A case statement with enum_t type in case expression:
enum_t case_expression;
logic [2:0] result;
case (case_expression)
ONE: result = 3'b000;
TWO: result = 3'b001;
THREE: result = 3'b010;
FOUR: result = 3'b011;
FIVE: result = 3'b100;
endcase
I'm not sure or clear about following :
Is it okay not to have a default case statement for result? The case_expression is an enum with only 5 valid values. However it's 3 bits. So how the synthesis tool will evaluate this logic? Is it going to infer latch ?
All case items are mutually exclusive. So can I use unique keyword here to aid synthesis tool to optimize the design?
I don't have much expereince in synthesis. So I would appreciate any feedback. Thanks!
This depends on how strongly typed your synthesis tool is. Unfortunately, there are a number of ways that your case_expression could have the value 3'b111 (through casting and poor error checking in some simulation tools). So its best to put the default in for safety's sake.
If "case_expression" takes the value "x", the case statement will not be able to resolve which case to enter. If default case were to be mentioned, it would gracefully enter the default case. You will see runtime error if case_expression takes value of "x" if default is not mentioned.
I believe "unique case" is a directive to synthesis tool mentioning all cases are enumerated. This would prevent a latch. If in simulation if none of the ENUM values are on the case expression, then during simulation a runtime error will be reported.

Is it ok to force value on an input port in Systemverilog?

I have this SV code :
module m1 (input int a);
always begin #1; force a=a+1; end
endmodule
module m ();
int a;
m1 m1(a);
endmodule
Is this statement in above code valid force a=a+1;?
It might work in your simulator, however it is not recommended.
In the IEEE std 1800-2009 section 10.6 defines a force statement as a "procedural continuous assignment." There is an example in the LRM stating that if a value on the right hand side of the equation is changes, then it will force the new value to the right hand variable. In this case a=a+1 should technically cause an infinite loop but likely does not because of a scheduling rule.
In general force should be used sparingly and be used in a test bench and behavioral modeling. Functional expressions are allowed with force however circular dependance needs to be avoided. Best to assign a constant expression with force is possible.
Yes, I believe the behavior is well defined in this case. Module m1 will see the forced value but the enclosing module will not.

Using blocking assignments to infer flip-flops in Verilog

I have read "Nonblocking Assignments in Verilog Synthesis, Coding Styles that Kill!" by Clifford Cummings. He says that the following code (page 12, simplified) is a correct implementation of a flip-flop often used in textbooks, even if not exactly the kind that anyone should use. The document won a best paper award, so I assume the claim is true.
module ff (q, d, clk)
output q;
input d, clk;
reg q;
always #(posedge clk)
q = d;
endmodule
I would like to know why this would continue to work correctly if two or more of these flip-flops were connected in series. Say
module two_ffs (q, d, clk)
input d, clk;
output q;
wire tmp;
ff firstff (tmp, d, clk);
ff secondff (q, tmp, clk);
endmodule
The way I see it, it's possible that the value of tmp is updated before it is used by secondff, thus resulting in one flip-flop rather than two. Can someone please tell me what part of the standard says that cannot happen? Many thanks.
[not that I would ever contemplate writing code like that, I just want to understand the blocking/nonblocking behavior even in cases when poor coding style makes the meaning non-obvious]
Added later:
I now think the paper is unlikely to be correct. Section 5 "Scheduling Semantics" of the 1364-2201 Verilog standard explains what happens. In particular, section 5.6.6 "Port connections" on page 68 says that unidirectional ports are just like continuous assignments. In turn, a continuous assignment is just an always block sensitive to everything. So the bottom line is that that the two instantiations of an ff in my example below are equivalent to a module with multiple always clauses, which everyone would agree is broken.
Added after Clive Cummings answered the question:
I am grateful to CC for pointing out that that the statements above taken out of section 5 of the standard only refer to the timing of update events, and do not imply literal equivalence between e.g. some continuous assignments and always blocks. Nevertheless, I think they explain why some simulators (e.g. Icarus Verilog) will produce different simulation results with a blocking and a non-blocking assignment in the "flip-flop". [On a larger example, I got 2 apparent ffs with a blocking assignment, and the correct five with a non-blocking one.] Other simulators (e.g. Modelsim with default options or Cver) seem to produce the same result no matter which form of assignment is used.
All -
A few corrections and updates. Section 5.6.6 of the 2001 Verilog Standard does not say that "unidirectional ports are just like continuous assignments," it says "Ports connect processes through implicit continuous assignment statements." There is a difference that I will note below.
Second, "a continuous assignment is just an always block sensitive to everything," is not true. Continuous assignments Drive values onto nets that can be driven by other sources with pre-defined resolution functions as described in the Verilog Standard. Always blocks Change values of variables and last procedural change wins (no resolution).
Regarding my description of the 1-always block flip-flop, my description in the paper is not 100% accurate (but is usually accurate). The 2-instantiated flip-flop model in theory does have a race condition, though it is rarely seen. The race is rarely seen because when you make an always block assignment to a variable that is declared as an output, Verilog compilers automatically throw in an "implicit continuous assignment statement" (IEEE-1364-2001, Section 5.6.6, 1st paragraph) to convert the procedural variable into a net-Driving assignment (you never see this happen!) This conversion is typically sufficient to introduce the equivalent of a nonblocking assignment delay on the port, so the simulation works. I have experimented in the past with compiler optimization switches that effectively remove the module ports between the flip-flops and have observed the unwanted race conditions, so technically, my description of an okay 1-always, blocking-assignment flip-flop is not 100% correct; hence, you should still use the nonblocking assignments described in the paper.
The 2-always blocking-assignment example in the same module has a definite race condition. As written, it will probably work because most compilers execute the code top-down, but if you reverse the order of the always blocks, you will probably see a race.
Regards - Cliff Cummings -
Verilog & SystemVerilog Guru
Reading Version 1.3 of the paper, Section 9 Example 13. The text under it explains that it is OK if the module only contains a single always block. My current understanding is that it is not an issue between separate modules. Allowing your example to work. However if a module contained multiple always blocks then the order of execution is undefined and will lead to the race conditions talked about in section 2 of the paper.
The example below is almost the same as the 2 flop example in the question, except it is in 1 module and so has an undefined order of execution, this will likely not work.
module ff (q, d, clk)
output reg q;
input d, clk;
reg d_delay ;
always #(posedge clk)
d_delay = d;
always #(posedge clk)
q = d_delay;
endmodule

Resources