Best VHDL design practice - vhdl

Question about best VHDL design practice.
When designing state machines, should I use a signal within the Architecture or use an variable. I have until now used variables, since they are "kinda" private to the process, and IMHO makes good sense because they should not be accesses outside the process. But is this good design practice?
type state_type is (s0,s1);
signal state : state_type := s0;
A : process(clk)
begin
if rising_edge(clk) then
case state is
.....
end case;
end if;
end process;
--This process uses a variable
B : process(clk)
type state_type is (s0,s1);
variable state : state_type := s0;
begin
if rising_edge(clk) then
case state is
.....
end case;
end if;
end process;

I prefer to use signals. The reason is that it allows the design to be split between multiple processes. One process can worry about how the state machine moves from state to state, and other processes can contain logic that is dependent on the state.
Doing it this way means you can have multiple simple processes that do one thing each. Using variables, everything has to go into the one process and that can become unwieldy.
It's a stylistic choice though.

I always use variables unless I need to communicate some value to another process. Because that's what signals are for.
Another potential benefit (or alternatively, something to watch as a violation of your coding standards!) of "localising the state variable" is that you can call the type and the variable state_type and state in two state machines in the same entity without them clashing...

For synthesis, I almost exclusively use signals.
Why?
Signals seem to be more universally understood.
Code clarity. Signals are all updated once, at the same time. Mixing variables and signals can be (potentially) confusing because you must remember that variable assignment takes effect immediately, whereas subsequent signal assignment implies priority. The value of a signal will never change during the same execution of a process.
Lower risk of deep logic paths. Inexperienced designers may be tempted to use variables like a C program, which would result in logic that will not meet timing goals.
Why Not?
Large designs end up with very long lists of signals and can be difficult to find the signal types/sizes/etc. Typically this only occurs for wrappers of the largest blocks in a design, and/or a design top level.
For testbench, I use variables and signals, depending on the use.

If the signal in this case it's not needed as an input or output of your process is a better use to use variables because when you're building the architecture you will need to assign a signal to the output of the module, and if it won't be used, it's not necessary to create the signal and spend more memory for something you won't use to connect to another module of your architecture.

Related

VHDL: Mealy machine and button press detection

Hi I'm a bit confused about the implementation of Mealy state machine using VHDL. My current work is like this:
process(clk, rst)
begin
if rst = '1' then
state <= s1;
elsif (clk'event and clk = '1') then
state <= next_state;
end if;
end process;
and another process like this:
process(state, op)
begin
case state is
when s1 =>
...some implementation
end process;
And now the problem is: I need to detect the press of the button from the user, but I'm not sure where to put it. Should it be inside the first process or the second process? Besides, I also looked through the following guide: implement state machine in FPGA, is it okay to use just one process for the Mealy machine as shown on the webpage? If it is so then I think the work will be easier. Thanks!
You should put it in the second process. The first process is only used to change states and the next_state is also calculated in the second.
There are several ways to write FSMs and people tend to favour one or the other for various reasons. Pick the one that works for you.
You cannot design a Mealy state machine with only one process. Even Moore state machines, in most cases, cannot be modelled with only one process.
A state machine always has a state register which must be modelled with a synchronous process. That is, a process which sensitivity list contains only the clock (and set or reset signals if they are asynchronous).
Every output of a synchronous process will synthesize as the output of a register because its value changes only on an edge of the clock (plus states of asynchronous set or reset if any). So, you cannot describe the outputs of a Mealy state machine in the same synchronous process as the state register. If you were doing so, it would not be a Mealy machine any more because its outputs would not combinationally depend on the inputs.
For Moore machines, things are a bit more subtle but, except in very exceptional cases, you also need at least two processes. When I write "process", I include processes short-hands like concurrent signal assignments, concurrent procedure calls or component/entity instantiations.
To make it simple: VHDL modelling for synthesis is straightforward if you have a clear view of the hardware you want.
Draw a block diagram of your hardware with registers and combinatorial parts clearly identified.
Draw bubbles enclosing hardware elements, one bubble per process, respecting the rule that if a bubble contains a register, all its outputs must be register outputs.
The synchronous processes are those enclosing registers. Their code is exactly:
process(clk)
begin
if rising_edge(clk) then
<your code>
end if;
end process;
Put your code in <your code>, never put code elsewhere. If you have asynchronous set or reset the code must be something like:
process(clk, reset)
begin
if reset = '1' then
<initialize outputs>
elsif rising_edge(clk) then
<your code>
end if;
end process;
The other processes are combinatorial processes. List all their entering signals (INPUTS) and output signals (OUTPUTS). The code must be:
process(INPUTS)
begin
<your code>
end process;
with the constraint that each OUTPUT signal must be assigned a value in every execution of the process. The best way to guarantee this is to start the process with a default assignment of all OUTPUTS.
That's all. Draw and code what you see. Bonus: every arrow crossing the border of one of your process-bubbles is a signal that you will have to declare unless it is already a primary input or output of your design.
Exercise: draw the block diagram of a Mealy state machine and understand why it cannot be modelled with one single process. Understand also why it can always be modelled with two processes, even if it is not necessarily desirable. Finally, try to identify the rare cases where a Moore state machine can be modelled with one process only.

what exactly is a variable in VHDL?

I know how to use variables in VHDL and what I can do with that, but I don't know exactly what it is in hardware ?
What is the difference between signals and variables in hardware and where the value of a variable store ?
Is it a wire or it depends on my code ?
According to the "QuantumRipple" comments I extend this question :
I synthesized the following simple code with ISE (Xilinx synthesis tool) and the variable (var) synthesized into a D flip flop ??
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY test IS
port(
clk : in std_logic;
input : in std_logic;
output : out std_logic
);
END test;
ARCHITECTURE Behavioral OF test IS
BEGIN
PROCESS(clk)
VARIABLE var : std_logic;
BEGIN
IF clk'event AND clk = '1' THEN
var := input;
END IF;
output <= var;
END PROCESS;
END Behavioral;
Thanks for comments and answers ...
Variables can be used in several functionally distinct ways. As a result, the synthesizer can implement them in several ways.
The following applies to clocked processes:
If you independently set the variable in a process before you read it, it will synthesize purely into [a group of] LUTs. (complicated logical functions or a vector variable will require more than one LUT even for a single assignment)
If you update a variable multiple times and read it between updates, it will synthesize into several [groups of] LUTs. This case is no different than if you created a different named variable for each update, read pair.
If you read the value of the variable before it is set in the process and assign it after all reads it will synthesize into a flip flop. Variables in this configuration behave equivalently to signals.
If you set the variable based of a combination of itself and another value before it is independently set, it will synthesize into an (unnamed) flip flop and a [group of] LUTs hanging off of that.
These can also be combined to an extent. For example, if you read a variable at the start of a process and assign it at the end, but also update and read the variable in the middle, it will generate a flip flop whose output is used for the first read, and also some LUTs whose output is used for the second read.
Multiple assignments without intermediary reads also get collapsed into one group of LUTs (nothing taps off of the intermediary value).
Another important thing to understand about how VHDL is synthesized is that signals and variables do not really get translated into specific things. A signal refers to a specific wire in the design (not the stuff in between like LUTs and Flip Flops). Signals that are assigned in clocked processes will usually refer to the Dout wire from a certain Flip Flop and signals that are assigned in a combinatorial process or concurrent statement will usually refer to a wire coming out of a LUT, although it might refer to the same wire as another signal (including clocked signals!) if there was no logic in the assignment (a simple a <= b).
The assignment statements describe the relationship between wires.
Variables do not refer to a fixed wire, but rather just describe behavior.
Each variable assignment that is used to assign something else before it is assigned again creates a reference to a different wire (although these wires will typically not be explicitly named like signal wires - that's the point of variables).
The synthesizer takes that behavior and tries to determine what set of LUTs and Flip Flops are required to make the hardware do that. Note that while signals refer to some fixed wires, they don't refer to all wires. The synthesizer creates many un-named (the synthesizer generates an arbitrary name) wires to connect the generated components (LUTs and flip flops) between each explicitly named wire. It is because variables are so flexible in what the describe (not a fixed wire) that they can cause the generation of so many different combinations of basic components depending on how they are used.
For your specific code, yes, the variable var will cause a flip flop to be synthesized.
It would also do the exact same thing if 'var' was a signal and the output <= var; assignment was outside of the process.
In your code, var is set based on the sole assignment to refer to the Dout wire of a clocked element (flip flop) that has a Din of input, then the output is assigned to refer to the same wire as var.
In fact, it does the exact same thing as just doing
IF clk'event and clk = '1' THEN
output <= input;
END IF;
in this case, output is just directly assigned to refer to the Dout wire of the clocked element that has a Din of input instead of using var as a proxy.

VHDL state machine differences (for synthesization)

I am taking a class on embedded system design and one of my class mates, that has taken another course, claims that the lecturer of the other course would not let them implement state machines like this:
architecture behavioral of sm is
type state_t is (s1, s2, s3);
signal state : state_t;
begin
oneproc: process(Rst, Clk)
begin
if (Rst = '1') then
-- Reset
elsif (rising_edge(Clk)) then
case state is
when s1 =>
if (input = '1') then
state <= s2;
else
state <= s1;
end if;
...
...
...
end case;
end if;
end process;
end architecture;
But instead they had to do like this:
architecture behavioral of sm is
type state_t is (s1, s2, s3);
signal state, next_state : state_t;
begin
syncproc: process(Rst, Clk)
begin
if (Rst = '1') then
--Reset
elsif (rising_edge(Clk)) then
state <= next_state;
end if;
end process;
combproc: process(state)
begin
case state is
when s1 =>
if (input = '1') then
next_state <= s2;
else
next_state <= s1;
end if;
...
...
...
end case;
end process;
end architecture;
To me, who is very inexperienced, the first method looks more fool proof since everything is clocked and there is less (no?) risk of introducing latches.
My class mate can't give me any reason for why his lecturer would not let them use the other way of implementing it so I'm trying to find the pros and cons of each.
Is any of them prefered in industry? Why would I want to avoid one or the other?
The single process form is simpler and shorter. This alone reduces the chance that it contains errors.
However the fact that it also eliminates the "incomplete sensitivity list" problem that plagues the other's combinational process should make it the clear winner regardless of any other considerations.
And yet there are so many texts and tutorials advising the reverse, without properly justifying that advice or (in at least one case I can't find atm) introducing a silly mistake into the single process form and rejecting the entire idea on the grounds of that mistake.
The only thing (AFAIK) the single-process form doesn't do well is un-clocked outputs. These are (IMO) poor practice anyway as they can be races at the best of times, and could be handled by a separate combinational process for that output only if you really had to.
I'm guessing there was originally some practical reason behind it; maybe a mid-1990s synthesis tool that couldn't reliably handle the single process form, and that made it into the original documentation that the lecturers learned from. Like those blasted non-standard std_logic_arith libraries. And so the myth has been perpetuated...
Those same lecturers would probably have a fit if they saw what can pass through a modern synthesis tool : integers, enumerations, record types, loops, functions and procedures updating signals (Xilinx ISE is now fine with these. Some versions of Synplicity have trouble with functions, but accept an identical procedure with an Out parameter).
One other comment : I prefer if Rst = '1' then over if (Rst = '1') then. It looks less like line noise (or C).
I agree with Brian on this. The only issue with the one process state machine is you cannot have un-clocked outputs, which is an issue if you need 0 latency on input to output. Otherwise the one process model helps to minimize bugs as it clearly relates the outputs to the state.
I was taught the two process model in school, but have discovered that the one process model is what is generally accepted in industry. I believe the reasoning for using the two process model in school is it gives students an understanding of how the placement of combinational logic relative to registers changes based on how the code is written (which IMO is very important when starting out) and what it means for their design. However simply forcing you to use the two process model with no explanation does not accomplish this.
the first method looks more fool proof since everything is clocked and there is less (no?) risk of introducing latches.
Yes, the first method where everything is clocked has no chance of introducing latches. It may introduce flipflops, but that's fine.
The 2nd method can introduce true asynchronous latches, which even in the best case are not very well handled by the back end FPGA tools I've used, and are not supported at all in some architectures, so would have to be built out of gates or lookup-tables.
In addition, if you get your sensitivity list wrong in the second process, your simulation can differ from your synthesis result! This is because synthesisers (for reasons I've given up trying to understand) treat the sensitivity list as if it were populated with all the signals you read (completely ignoring the VHDL language spec in the process) whereas the simulator will do exactly what you said.
Ugh. I hate the dual process state machine thing personally. He is probably an old guy and this was the most reliable way to do it 20 years ago. The tools understand your way and I personally like that approach better.
Your classmate is absolutely right. The problem here is that your question is not complete. The reason for your colleague's code to be better than yours is that people normally define the output values and the next state values in the same process, as shown below (this is the same as your own code, just with the output values added to it, which results in a "bad"code):
elsif (rising_edge(clk)) then
case state is
when s1 =>
--define outputs:
outp1 <= ...;
outp2 <= ...;
...
--define next state:
if (input = '1') then
state <= s2;
else
state <= s1;
end if;
when s2 =>
...
...
end case;
end if;
Recall that in an FSM the output is produced by the combinational logic section, therefore it is memoryless. However, in the code above, the output values get registered, which is not what the FSM must produce. Indeed, registering the outputs is a case-by-case decision EXTERNAL to the FSM (the outputs could be registered, for example, for glitch removal, which is a PARTICULAR, PLANNED decision, not a FORCED situation, as in the code above).

Is the use of records the solution to all latch problems in VHDL

I was recently told that the solution to all (most) problems with unintended latches during VHDL synthesis is to put whatever the problematic signal is in a record.
This seems like it's a little bit too good to be true, but I'm not that experienced with VHDL so there could be something else that I'm not considering.
Should I put all my signals in records?
No, you should not put all your signals in records. This will quickly become very confusing and you will not gain anything by using the record.
One way that a record may help you avoid latches, is if you register an entire record in a clocked process, you are really registering all of the components of the record. This takes one line of code, instead of possibly tens of lines. In the case where you have many elements which all need to be treated the same, a record can save you "silly mistakes", and possibly save you from creating a latch.
As stated by others, a record doesn't have any specific synthesis interpretation. It is simply a group of signals that you are grouping together for coding-convenience.
I don't see how this would help - a record (or even just parts of a record) can become a latch just as easily as a signal. A latch is generated if a signal keeps its state through some combinatorial process (i.e., is not assigned a value on ALL paths through the process). The same holds for constituents of a record.
Records can be useful to group related signals for readability, but synthesis-wise a record is pretty much equivalent to a bunch of individual signals.
My personal suggestion to avoid latches: avoid combinatorial processes. Make all processes clocked, and do combinatorial logic at the architecture level.
A record is just another way of grouping other types, similar to using an array
for grouping of a std_logic to std_logic_vector, so there is nothing
magical about records that make them better for avoiding latches in a design.
If you get unintended latches in your design, what I guess you think of as
"latch problems", it is because you coding style specifies latches, and you
should change the coding style, as #zennehoy also suggests.
One approach can be to define some code templates for different constructions
that you use, and then stick to these known and working templates.
The template for a flip-flop (FF) with asynchronous reset can be:
process (clk_i, rst_i) is
begin
-- Clock
if rising_edge(clk_i) then
... Control structures with Qs assign by function for Ds
... Synchronous reset is just another branch
end if;
-- Reset (asynchronous) if required
if rst_i = '1' then
... Qs assign with constant reset value for so or all Qs
end if;
end process;
Use concurrent signal assigns when possible, and more complex expressions can
be done through use of concurrent function call, where a function is used
outside a process like:
z_o <= fun(a_i, b_i);
If a process is used to create combinatorial logic, then a common pitfall and
cause for latches in VHDL is to forget a signal in the sensitivity list.
However, VHDL-2008 has a solution for this, since you can use (all) as
sensitivity list, whereby all signal used in the process are implicitly
included in the sensitivity list. So if you use VHDL-2008, then your template
for combinatorial processes can be:
process (all) is
begin
z_o <= a_i and b_i;
end process;
These template should be all you need for typical synthesizable design, and
these will keep your design latch free.

VHDL Structural vs Behavioral

This is a question for those who have a good understanding of VHDL. I'm a newbie but so far I have been generating VHDL using a behavioral description. For me it is much easier to think about as it is similar to writing software. I am aware that a possible downfall is that behavioral 'executes' sequentially while structural executes concurrently within the design component/process..
So I'm just curious, if I have an architecture that uses a process for say an 8-bit shift register (SISO) and I want to create 4 instances of these (4x8-bit shift registers) would I create a component and 4 instances of the process?
Or would I generate 4 processes (executing in parallel to one another) and just call each process by a different name?
Also, just a general question to get a consensus of what good practices people use out there, which do you prefer: structural vs. behavioral?? When would be a good time to choose one over the other? I'm guessing their could be some benefits with 'faster' execution using components that allow internal concurrency vs. sequential execution in processes.. It sure does seem to me though that one could reduce the design time with behavioral designs..
Thanks!
~doddy
For my money, the role of structural HDL nowadays is restricted to interconnecting tested working behavioral blocks (or connecting untested ones to their testbenches!) - I would agree with you about the superiority of behavioural VHDL in terms of design creation and test time.
I would also agree that writing a behavioural process is in some ways similar to writing software (over the screams of some that it isn't)
HOWEVER
do not fall into the trap of equating behavioural with sequential or slow!
Given your shift register, say
type reg_type is array(7 downto 0) of bit;
signal s_in, s_out : bit;
process(clk) is
variable reg : reg_type;
begin
if rising_edge(clk) then
s_out <= reg(7);
reg := reg(6 downto 0) & s_in;
end if;
end;
I can trivially parallelise it as follows:
signal p_in, p_out : array(1 to 4) of bit;
process(clk) is
variable reg : array(1 to 4) of reg_type;
begin
if rising_edge(clk) then
for i in reg'range loop
p_out(i) <= reg(i)(7);
reg(i) := reg(i)(6 downto 0) & p_in(i);
end loop;
end if;
end;
(And yes there are simpler ways to write this!)
It is important to note that the loop does not take any longer to run : it just generates more hardware (in software terms, it is unrolled completely). Each iteration is completely independent of the others; if they weren't, things would be more complex.
Don't worry about the academic differences between structural and behavioral.
Worry about the difference between signal assignment scheduling and variable assignment scheduling in a process (learn what delta cycles and postponed assignment are - this is one of the key diffs from software, and arises because software only has variables, not VHDL's signals). That will explain why I implemented the pipeline upside down here (output first) - because I used a variable.
Worry about why so many people teach the idiotic 2-process state machine when the 1-process SM is simpler and safer.
Find and understand Mike Treseler's pages about single-process models (I hope they are still online)

Resources