What is the difference between structural Verilog and behavioural Verilog? - verilog

As in the title, what are the main differences between structural and behavioural Verilog?

There is no strict definition of these terms, according to the IEEE Std. However, customarily, structural refers to describing a design using module instances (especially for the lower-level building blocks such as AND gates and flip-flops), whereas behavioral refers to describing a design using always blocks.
Gate netlists are always structural, and RTL code is typically behavioral. It is common for RTL to have instances of clock gates and synchronizer cells.

Structural
Here functions are defined using basic components such as an invertor,
a MUX, a adder, a decoder, basic digital logic gates etc.. It is just
like connecting and arranging different parts of circuits available to
implement a function.
Behavorial
The Behavioral description in Verilog is used to describe the function
of a design in an algorithmic manner. Behavioral modeling in Verilog
uses constructs similar to C language constructs. Further , this is
divided into 2 sub categories .
(a) Continuous
assignment of data to outputs are continuous. This will be
implemented using explicit "assign" statements or by assigning a
value to a wire during its declaration .
In case of assign any change in input will
immediately effect the output . Hence output is to be declared as
wire
(b) Procedural
Here the data assignments are not carried out continuously instead it
happens on specific events specified in sensitivity list. This type of
modelling scheme is implemented using procedural blocks such as
"always"or "initial" .
Here, output variables must be defined as reg because they need to
keep hold of previous value until new assignment occurs after any change in specified sensitivity list.
Hope this helps :)

Structural Verilog is usually referred to a Verilog code which is synthesizable (has an accurate and meaningful hardware realization) and is usually written in Register Transfer Level (RTL).
On the other hand Behavioral Verilog is usually a behavioral description of a hardware or functionality on a higher level. behavioral code does not have to be synthesizable for example when you define a delay in your verilog code scaled by the timescale, the synthesizer does not consider it when it is translating your code into logic and hardware, but rather it has simulation purposes.
The same goes for structural and behavioral VHDL.

Behavioral doesn't use logic gates description you can use And,Or,Not gates that are already defined in verilog
while structural uses logic gates description where you describe that you want a module called (And/Or/Not) and describe what it does & / | / ~.

Structural verilog deals with the primitives in simple word like and, or, not etc..
The primitives are called/inferred from libraries and connected with input output ports.
Example
module structural(y,a,b);
input a,b;
output y;
and a1 (y,a,b); // and is the primitive inferred and a1 is the instance name.
endmodule
Behavioral verilog deals with the logic or behavior of a system. It handles complex logic implementation and which is why in industry all implement the behavioral models of the system called as RTL. Once the behavioral RTL is validated by front end engineers using SV/UVM then this RTL is converted into Gate Level i.e Structural which go for synthesis.
Please refer the book of verilog written by Samir Palnitkar for more details.

Verilog is both a behavioral and a structural language. Internals of each module can be defined at four levels of abstraction, depending on the needs of the design.
Structural Verilog describes how a module is composed of simpler modules or of basic primitives such as gates or transistors. Behavioral Verilog describes how the outputs are computed as functions of the inputs.
Behavioral level
->This is the highest level of abstraction provided by Verilog HDL. mainly construct using
"always" and "initial" block.
Dataflow level
-> At this level, the module is designed by specifying the data flow. condition describe using "assign" keyword.
Gate level
->The module is implemented in terms of logic gates and interconnections between
these gates.
Switch level
->This is the lowest level of abstraction provided by Verilog. A module can be
implemented in terms of switches, storage nodes, and the interconnections
between them.

Related

How to unpack LUTs into logic cells in verilog

I have a structural verilog containing LUTS all over him.
I want this verilog to be unpacked so that I'll have the same functional but instead LUTS - I'll have logic cell (Like Or/And/Xor etc...).
How can I do it ?
Does Yosys has something built in ?
Is there something else out there over the internet who already implement that kind of thing ?
Because I searched for this and I could not find.
You could do something like the following
read_verilog struct.v lut.v
hierarchy -top top
flatten
synth -noabc
in Yosys, where lut.v contains a Verilog model of the LUT primitive. This would convert LUTs to non-optimised logic. You could also use abc (remove -noabc, or add abc at the end of the script) to optimise the logic.

Incomplete assignment and latches

When incompletely assigning a value I get a latch. But why did I get a latch in the example below? I think there is no need for the latch of F output because it is defined at all values of SEL.
Verilog code:
always # (ENB or D or A or B pr SEL)
if (ENB)
begin
Q=D;
if (SEL)
F=A;
else
F=B;
end
Inferred logic:
Although it is defined at all values of SEL, it is not defined for all values of ENB. If ENB = 0, your code says that both Q and F should hold the value from the previous cycle. This is also what is inferred in the image you are linking: only update Q and F if ENB = 1.
If you want Q to be a latch and F not, you can do this:
always # (ENB or D or A or B or SEL)
begin
if (ENB)
Q=D;
if (SEL)
F=A;
else
F=B;
end
Edit: additional information
As pointed out in the comments, I only showed how you could realize combinational logic and a latch, without modifying your code too much. There are, however, some things which could be done better. So, a non-TL;DR version:
Although it is possible to put combinational logic and latches in one procedural block, it is better to split them into two blocks. You are designing two different kinds of hardware, so it is also better to seperate them in Verilog.
Use nonblocking assignments instead of blocking assignments when modeling latches. Clifford E. Cummings wrote an excellent paper on the difference between blocking and nonblocking assignments and why it is important to know the difference. I am also going to use this paper as source here: Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!
First, it is important to understand what a race condition in Verilog is (Cummings):
A Verilog race condition occurs when two or more statements that are scheduled to execute in the same simulation time-step, would give different results when the order of statement execution is changed, as permitted by the IEEE Verilog Standard.
Simply put: always blocks may be executed in an arbitrary order, which could cause race conditions and thus unexpected behaviour.
To understand how to prevent this, it is important to understand the difference between blocking and nonblocking assignments. When you use a blocking assignment (=), the evaluation of the right-hand side (in your code A, B, and D) and assignment of the left-hand side (in your code Q and F) is done without interruption from any other Verilog statement (i.e., "it happens immediately"). When using a nonblocking assignment (<=), however, the left-hand side is only updated at the end of a timestep.
As you can imagine, the latter assignment type helps to prevent race conditions, because you know for sure at what moment the left-hand side of your assignment will be updated.
After an analysis of the matter, Cummings concludes, i.a., the following:
Guideline #1: When modeling sequential logic, use nonblocking assignments.
Guideline #2: When modeling latches, use nonblocking assignments.
Guideline #3: When modeling combinational logic with an always block, use blocking assignments.
A last point which I want to highlight from the aforementioned paper is the "why". Except from the fact that you are sure the right hardware is infered, it also helps when correlating pre-synthesis simulations with the the behaviour of your actual hardware:
But why? In general, the answer is simulation related. Ignoring the above guidelines [about using blocking or nonblocking assignments on page 2 of the paper] can still infer the correct synthesized logic, but the pre-synthesis simulation might not match the behavior of the synthesized circuit.
This last point is not possible if you want to strictly adhere to Verilog2001, but if you are free to choose your Verilog version, try to use always_combfor combinational logic and always_latch for latches. Both keywords automatically infer the sensitivity list, and it is easier for tools to find out if you actually coded up the logic you intended to design.
Quoting from the SystemVerilog LRM:
The always_latch construct is identical to the always_comb construct except that software tools should perform additional checks and warn if the behavior in an always_latch construct does not represent latched logic, whereas in an always_comb construct, tools should check and warn if the behavior does not represent combinational logic.
With these tips, your logic would look like this:
always_latch
begin
if (ENB)
Q <= D;
end
always_comb
begin
if (SEL)
F = A;
else
F = B;
end

What is "net" in HDL synthesis

I am a beginner in circuit synthesis, and I came across the word net a lot, but I am never able to find its standard definition. It seems to me that it refers to any kind of "black box" where it receives inputs and produce outputs. So it can be a sub circuit inside a big circuit and it can be an array of gates. Is my understanding correct?
No, your understanding is not correct.
Verilog
In Verilog, net has a precise definition:
IEEE 1800-2012 states:
6.5 Nets and variables
There are two main groups of data objects: variables and nets. These two groups differ in the way in which they
are assigned and hold values.
A net can be written by one or more
continuous assignments, by primitive outputs, or through module ports.
The resultant value of multiple drivers is determined by the
resolution function of the net type. A net cannot be procedurally
assigned.
A net can be one of many types, for example: wire, supply0, wand, but by far the most common type is wire.
IEEE 1800-2012 goes on to say:
Variables can be written by one or more procedural statements,
including procedural continuous assignments. The last write determines
the value. Alternatively, variables can be written by one continuous
assignment or one port.
The main difference between the behaviour of a variable and a net is their behaviour when assigned to from more than one place, as highlighted by the bold text in the two quotes:
For a net, if you assign to it from more than one place, its resulting value is determined by a resolution function, which for the built-in net types (wire etc). The behaviour of the resolution function depends on the net type and that is the difference between the net types. So, for example, with a wire, if both 1'b0 and 1'b1 are assigned to it, the resulting value will be 1'bx (unknown) if both assignments assign values with the same strength. The resolution function is intended to model real electronics. (There is also the added complication of user-defined net types and drive strengths, but let's leave those out for this discussion.)
For a variable, if you assign to it from more than one place, its resulting value is determined by whatever value is written last (just like a normal software variable). So, for example, if a 1'b0 is assigned and then a 1'b1 is assigned, the resulting value will be 1'b1 because that value was assigned last. There is no resolution function involved nor any concept of drive strength.
Both nets and variables are used to model combinational logic and sequential logic. There are rules for when you can use a net and when you can use a variable and the choice of which to use is governed by those rules (given in the quotes above). These were strict in verilog, but have been relaxed in System-Verilog to such an extent that, if you are not designing using tri-state logic, you don't need nets in System-Verilog.
VHDL has exactly the same distinction. The VHDL equivalent of a Verilog net is a signal; the VHDL equivalent of a Verilog variable is a variable. The rules about which to use where in VHDL are different, however, and more strict (no surprise there).
Electronics
In electronics a net means a piece of metal through which current flows. In other words, a net is the connection between one place and another. Physically, it could be a PCB track, a cable, a bond wire or a metal connection on an IC. Generally, in digital electronics, it is most like to be a metal connection on an IC.
Synthesis
So, to answer your question, if someone uses the term "net" when talking about the output of a logic synthesiser (the gate-level netlist), they almost certainly mean the second idea: the construct in whatever format that gate-level netlist uses that models the connection between one gate and another. As it is common for synthesisers to output their gate-level netlist as Verilog, those connections between gates are probably modeled using Verilog nets anyway (probably wires).

Verilog design - input is "unused" warning

When attempting to synthesize a Verilog design (I want to generate a schematic), I get the following warning:
Synthesizing Unit <rising>.
Related source file is "C:\PPM\PPM_encoder\detectors.v".
WARNING:Xst:647 - Input <in> is never used. This port will be preserved and left unconnected if it belongs to a top-level block or it belongs to a sub-block and the hierarchy of this sub-block is preserved.
Summary:
no macro.
Unit <rising> synthesized.
The relevant module is simply:
module rising (in, out);
output out;
input in;
not #(2,3) (ininv, in);
and #(2,3) (out, in, ininv);
endmodule
And I call it in several different locations, including:
rising startdetect(
.in(start),
.out(or01a));
When I complete the synthesis and then choose to "View schematic", only one component is actually present. Expanding that component, I see only the output being connected to ground, which is the initial condition. Nothing else is present. This is with my testbench as my "top module".
When I select my actual main project (below the testbench, it's called ppmencode) as the top module, I get those same warnings, plus additional warnings for every single module instance:
WARNING:Xst:1290 - Hierarchical block <startdetect> is unconnected in block <ppmencode>.
It will be removed from the design.
What is the cause of these two warnings, and how can I fix them and be able to generate a correct schematic?
Edited to add: The whole thing simulates perfectly, it's just when trying to make a schematic (to try to explain this thing that I just made to my team) that I run into problems. This image shows the schematic that I get.
It's not enough to have a signal named as an input to a module...it needs to actually be connected to a pin on the FPGA. On the other hand, your rising module is taking the AND of the input and its complement...the synthesizer might have figured out a way to simplify that logic that is contrary to your wishes.
Synthesis is optimizing all the logic out because it ignores the delays. Functionally you have in & ~in which is always 0. What you intend is a pulse generator. One way to achieve this is to use the dont_touch attribute, which tell the synthesizer that it must keep a particular module instantiation in the design. See this Properties Reference Guide for more.
module rising (in, out);
output out;
input in;
(* DONT_TOUCH = "TRUE" *)
not #(2,3) (ininv, in);
and #(2,3) (out, in, ininv);
endmodule
Be warned that even with the dont_touch your synthesize result may not match simulation. Synthesis ignores the artificial timing in your netlist. The actual pulse width could be longer, more likely shorter or to small to be registered. Check your standard cell library and look for a delay cell to apply to ininv, this will increase the pulse width. The library may already have a pulse generator cell already defined.

Verilog Best Practice - Incrementing a variable

I'm by no means a Verilog expert, and I was wondering if someone knew which of these ways to increment a value was better. Sorry if this is too simple a question.
Way A:
In a combinational logic block, probably in a state machine:
//some condition
count_next = count + 1;
And then somewhere in a sequential block:
count <= count_next;
Or Way B:
Combinational block:
//some condition
count_en = 1;
Sequential block:
if (count_en == 1)
count <= count + 1;
I have seen Way A more often. One potential benefit of Way B is that if you are incrementing the same variable in many places in your state machine, perhaps it would use only one adder instead of many; or is that false?
Which method is preferred and why? Do either have a significant drawback?
Thank you.
One potential benefit of Way B is that if you are incrementing the same variable in many places in your state machine, perhaps it would use only one adder instead of many; or is that false?
Any synthesis tool will attempt automatic resource sharing. How well they do so depends on the tool and code written. Here is a document that describes some features of Design Compiler. Notice that in some cases, less area means worse timing.
Which method is preferred and why? Do either have a significant drawback?
It depends. Verilog(for synthesis) is a means to implement some logic circuit but the spec does not specify exactly how this is done. Way A may be the same as Way B on an FPGA but Way A is not consistent with low power design on an ASIC due to the unconditional sequential assignment. Using reset nets is almost a requirement on an ASIC but since many FPGAs start in a known state, you can save quite a bit of resources by not having them.
I use Way A in my Verilog code. My sequential blocks have almost no logic in them; they just assign registers based on the values of the "wire regs" computed in the combinational always blocks. There is just less to go wrong this way. And with Verilog we need all the help we can get.
What is your definition of "better" ?
It can be better performance (faster maximum frequency of the synthesized circuit), smaller area (less logic gates), or faster simulation execution.
Let's consider smaller area case for Xilinx and Altera FPGAs. Registers in those FPGA families have enable input. In your "Way B", *count_en* will be directly mapped into that enable register input, which will result in less logic gates. Essentially, "Way B" provides more "hints" to a synthesis tool how to better synthesize that circuit. Also it's possible that most FPGA synthesis tools (I'm talking about Xilinx XST, Altera MAP, Mentor Precision, and Synopsys Synplify) will correctly infer register enable input from the "Way A".
If *count_en* is synthesized as enable register input, that will result in better performance of the circuit, because your counter increment logic will have less logic levels.
Thanks

Resources