Consider this VHDL code:
process(a, b)
begin
equal <= '0'; --default
gt <= '0'; --default
if a=b then
equal <= '1';
end if;
if a>b then
gt <= '1';
end if;
end process;
The so called 'default' values are supposed to protect from having latches for signals gt and equal. But since this is not a clocked process shouldn't this be an error of multiple drivers for signals gt and equal?
This is not a multiple drive situation because your signals are driven by one single process (unless you also drive them from another process, of course). So it is fine. What puzzles you, maybe, is when the same signal is assigned several times during the same process execution. The complete and detailed answer is far too complex for this short answer. But to make it simple, if you use only simple signal assignments (no after clause, no waveforms...), then the last assignment wins.
The reason is that each time the gt <= <value> instruction is executed, the <value> is not assigned immediately to signal gt. Instead it is recorded somewhere in the simulator's memory as the value to assign to signal gt at the end of the current simulation step. And at the end of the current simulation step, after all processes have been executed and are suspended on a wait statement (or on their sensitivity list, which is equivalent to a wait statement) the simulator updates signal gt with the recorded value.
So, if you execute, in the same simulation step:
gt <= '0';
...
gt <= '1';
the second assignment will overwrite the value recorded by the first assignment and gt will take value '1' at the end of the simulation step.
Related
I have a fundamental question on VHDL.
Consider the following process:
process(Clk)
begin
if(rising_edge(Clk)) then
a <= data_in;
b <= a;
c <= b;
data_out <= c;
end if;
end process;
The above process acts as a delay register, where data_in is output to data_out after 4 clock cycles.
From my understanding this happens because signals are assigned parallelly. But then why does the statements inside a process called sequential?
For example:
process(Clk)
begin
if(rising_edge(Clk)) then
a <= b or c;
a <= b and c;
end if;
end process;
In the above process the 'a' takes the value from the 2nd statement and I understand, how it works in a sequential way unlike the first process.
Please help.
It's actually very simple: all statements inside a VHDL process are executed sequentially, in order, from top to bottom, no exceptions. However,
the left hand side of a signal assignment operator (<=) does not
take its new value until the process (and all other processes) have
suspended (either hit the bottom or hit a wait statement) and
if you assign to a signal again (as in your second example) the last
assignment executed overwrites the previous ones.
Now you know that, simulate the above two processes in your head and you will see that they behave as you say they will. (The statements in your first example are NOT executed in parallel. But because of (1) above, it seems like they are.)
I am reading the book Free Range VHDL and here is an example of chapter 8.
-- library declaration
library IEEE;
use IEEE.std_logic_1164.all;
-- entity
entity my_fsm1 is
port ( TOG_EN : in std_logic;
CLK,CLR : in std_logic;
Z1 : out std_logic);
end my_fsm1;
-- architecture
architecture fsm1 of my_fsm1 is
type state_type is (ST0,ST1);
signal PS,NS : state_type;
begin
sync_proc: process(CLK,NS,CLR)
begin
-- take care of the asynchronous input
if (CLR = '1') then
PS <= ST0;
elsif (rising_edge(CLK)) then
PS <= NS;
end if;
end process sync_proc;
comb_proc: process(PS,TOG_EN)
begin
Z1 <= '0'; -- pre-assign output
case PS is
when ST0 => -- items regarding state ST0
Z1 <= '0'; -- Moore output
if (TOG_EN = '1') then NS <= ST1;
else NS <= ST0;
end if;
when ST1 => -- items regarding state ST1
Z1 <= '1'; -- Moore output
if (TOG_EN = '1') then NS <= ST0;
else NS <= ST1;
end if;
when others => -- the catch-all condition
Z1 <= '0'; -- arbitrary; it should never
NS <= ST0; -- make it to these two statements
end case;
end process comb_proc;
end fsm1;
Is there any difference if I remove NS from the sensitivity list of sync_proc?
sync_proc: process(CLK,NS,CLR)
begin
-- take care of the asynchronous input
if (CLR = '1') then
PS <= ST0;
elsif (rising_edge(CLK)) then
PS <= NS;
end if;
end process sync_proc;
After examining the question this is considered a duplicate of as well as it's answer lacking any authoritative reference as to when a signal belongs in the sensitivity list it may be worth asking where is that information derived from?
You could note Free Range VHDL only mentions wait as a reserved word in VHDL. There's much more to it than that. A process statement described in the VHDL standard (IEEE Std 1076-2008 10.3 Process statement) tells us:
If a process sensitivity list appears following the reserved word process, then the process statement is assumed to contain an implicit wait statement as the last statement of the process statement part; this implicit wait statement is of the form
wait on sensitivity_list ;
And then goes on to dicuss how the rules of 10.2 Wait statement are applied to a sensitivity list consisting of the reserved word all.
The syn_proc from architecture fsm1 of entity my_fsm1 from Free Range VHDL Listing 7.1 Solution to Example 18 has a sensitivity list in accordance with the rules found in 10.2 Wait statement for an implicitly generated sensitivity.
However, that's not the complete set of authorities. There's also IEEE Std 1076.6-2004 (RTL Synthesis, now withdrawn) 6.1.3.1 Edge-sensitive storage from a process with sensitivity list and one clock:
d) The process sensitivity list includes the clock and any signal controlling an <async_assignment>.
Where <async_assignment> is defined in 6.13 Modeling edge-sensitive storage elements:
<async_assignment>. An assignment to a signal or variable that is not controlled by <clock_edge> in any execution path.
And <clock_edge>is defined by convention (1.4) as one of the forms for clock_edge defined in BNF found in 6.1.2 Clock edge specification.
(translation: d) above means what you think it means when you read it.)
This tells us what signals are necessary here. There are no restrictions on unnecessary signals in the process sensitivity list. However their effect can be discerned from IEEE Std 1076-2008 10.2 Wait statement:
The suspended process also resumes as a result of an event occurring on any signal in the sensitivity set of the wait statement. If such an event occurs, the condition in the condition clause is evaluated. If the value of the condition is FALSE, the process suspends again. Such repeated suspension does not involve the recalculation of the timeout interval.
For a wait statement:
wait_statement ::=
[ label : ] wait [ sensitivity_clause ] [ condition_clause ] [ timeout_clause ] ;
it helps if you know the condition clause is optional as indicated by the square brackets above:
The condition clause specifies a condition that shall be met for the process to continue execution. If no condition clause appears, the condition clause until TRUE is assumed.
That means the process will resume for any event on any of the signals in the process sensitivity list and will traverse it's sequential statements.
There is no harm to the state of the design hierarchy during simulation by executing the sync_proc for an event on signal NS. Neither assignment statement in the if statement subject to conditions will execute. You could also note the same holds true for an event on the falling edge of CLK.
The objective in paring the sensitivity list is to minimize the number of times the process is resumed needlessly. The bigger more complex the design model the slower simulation will proceed, particularly dragging around needless resumptions and suspensions.
Of the three signals shown in the process sensitivity list only three binary value transitions are of interest, and none on signal NS. The current value of NS is assigned to PS on the rising edge of CLK.
A process suspends and resumes in a particular wait statement. A process with a sensitivity list shall not contain an explicit wait statement (10.3), meaning it will have only one wait statement, the implicit one.
It would seem with your first question on VHDL here you've reached beyond the limits of answers the book Free Range VHDL can supply.
A better entreaty on the subject might be The Designer's Guide to VHDL, 3rd edition by Peter Ashenden.
The idea being conveyed here that you can't get why without knowing how.
We always use process block with clock and reset in sensitivity list to describe sequence circuit.And use process block with every driver signals in sensitivity list to describe combinational circuit.
Sometimes sensitivity list is only important for simulations but if you forget a signal or add too many signals in sensitivity list you may get the wrong simulation result. Most time the real FPGA function will work fine if your logic is correct.
But it can cause some problem.
For example, if you describe a function like a=b&c in an always block with sensitivity (b); But you forget c. Then in your simulation a will not change when c is changed. But the circuit in real FPGA, will be the correct description of the function a=b&c. And you may get a warning when you synthesize your code.
You can call it ‘pre-sim and post-sim inconsistent’.
The real scary thing is that your pre-sim is right but your post-sim is wrong. That may cause the FPGA to incorrect function.
So I advise you to describe the circuit than the function when you write VHDL code.
I'm trying to work through an example of the WAIT ON statement. Every time I try to compile my code the the compiler, Quartus II gives me the following error message.
Error (10533): VHDL Wait Statement error at T1.vhd(23): Wait Statement must contain condition clause with UNTIL keyword
The model Architecture is below. Its function is not important only the reason why the compiler is asking for a UNTIL statement. All the examples I have seen, internet and books show its use as such below:
ARCHITECTURE dflow OF T1 IS
SIGNAL middle : std_logic;
BEGIN
P1 : PROCESS IS
BEGIN
IF CLK = '1' THEN
middle <= input;
END IF;
WAIT ON CLK;
END PROCESS P1;
OUTPUT <= MIDDLE;
END ARCHITECTURE dflow;
I think the basic problem here is that the line
WAIT ON CLK;
is waiting for any type of event on CLK. This could be a transition from 'H' to '1', for example, or it could be either a rising OR falling edge of CLK. In either of these cases, there is no real hardware in the FPGA that can work in this way. It may seem obvious to you that you are looking for a rising edge, because of the if CLK = '1' line, but this is not how the synthesis tool is seeing it.
By adding an until, you can narrow down which particular event you are interested in, hopefully selecting something that can actually be realised in the FPGA. Examples:
wait on clk until clk = '1'; -- Detect a rising edge, OK (ish, see below)
wait on clk until clk = '0'; -- Detect a falling edge, OK (^^)
This method is analogous to the clk'event and clk = '1' technique of edge detection. This is not a recommended method, because you can get a simulation mismatch with reality due to the simulator responding to transitions from 'H' to '1' (among other possibilities), something the hardware cannot do.
The recommended method of detecting edges is with the rising_edge and falling_edge functions:
wait until falling_edge(clk); -- OK, no ambiguity here.
Finally, the whole structure represented here looks pretty non-standard. The common way to write a clocked process is like this:
process (clk)
begin
if (rising_edge(clk)) then
-- Do something
end if;
end process;
My question is in regards to the following code:
library ieee;
use ieee.std_logic_1164.all;
entity exam is port (
I,CLK,RESET : in std_logic;
Q : out std_logic
);
end entity;
architecture exam_arc of exam is
signal temp_sig : std_logic;
begin
process (CLK,RESET)
begin
if RESET = '1' then
temp_sig <='0';
elsif CLK'event and CLK='1' then
temp_sig <= I;
end if;
Q <= temp_sig;
end process;
end exam_arc;
It seems that this piece of code simulates a D flip flop that operates on rising edge of the clock, however the answer [this question is taken from an exam] to this question claims that this D flip flop operates on falling edge of the clock.
What kind of flip flop this VHDL code simulates?
It's a trick question. Note that the process wakes up on both rising and falling clock edges, and that the intermediate signal temp_sig is assigned on the rising_edge.
Put that together with the semantics of signal assignment (postponed assignment) and see what you get.
Cross check via simulation as Jim suggests...
Separate the assignment to Q into it's own process statement with the same sensitivity list. The simulation models behavior will be identical although they vary in the number of processes.
DUT:
process (CLK,RESET)
begin
if RESET = '1' then
temp_sig <='0';
elsif CLK'event and CLK ='1' then
temp_sig <= I;
end if;
-- Q <= temp_sig;
end process;
QDEVICE:
process (CLK, RESET)
begin
Q <= temp_sig;
end process;
The edge sensitive storage device assigning temp_sig is clearly a positive edge clocked flip flop sensitive to CLK and asynchronously reset by RESET (high).
Is the QDEVICE process a synthesis target construct? It behaves as a follower latch to the temp_sig flip flop, but there is no indication as to the polarity of an enable. See IEEE Std 1076.6-2004 IEEE Standard for VHDL Register
Transfer Level (RTL) Synthesis, 6.2.1.1 Level-sensitive storage from process with sensitivity list:
A level-sensitive storage element shall be modeled for a signal (or variable) when all the following apply:
c) There are executions of the process that do not execute an explicit
assignment (via an assignment statement) to the signal (or variable).
Without qualification (by level) rule c is not met. Further in the original process you cite the behavior doesn't map to one of the IEEE Std 1076.6-2004 6.2 Clock edge specifications none of which include using an intermediary signal.
Brian is right it's a trick question. A flip flop with a follower-something-else providing delay. And the 'U' value in the simulation for q until an event on CLK or RESET should be telling.
You could just synthesize it yourself.
See also ffv3 http://www.cs.uregina.ca/Links/class-info/301/register/lecture.html which is almost the same.
Update
I was missguided by the missing formatting – in fact it actually is toggling on the falling edge as another answer already shows.
Although all asignments are done in sequence, signal assignments still happen at the end of the process, and thus temp_signal is half a clock cycle old (next falling edge) and does not contain the recently asigned value.
http://www.gmvhdl.com/process.htm
How does signal assignment work in a process?
Have you simulated it? When does Q change and why? When do signals update? During a rising edge, does Q get the value of I? Make sure to simulate it.
Lets look at the following line of code:
elsif CLK'event and CLK='1' then
CLK is your timing signal (aka the clock).
CLK'event is triggered when there is a change in the value of CLK.
CLK='1' means that the clock is equal to high.
So if the clock has changed and it is currently in the high state then we will execute the code within this ELSIF statement.
We know that there are only 2 states for bit variables, so if CLK changed AND it changed to a high state then it was originally in a low state. This means that the code will only execute when the clock goes from low to high.
If you wanted to execute on a high to low trigger then you would change the statement to read like this:
elsif CLK'event and CLK='0' then
In VHDL, in a process all steps will be executed sequentially, but I wonder how an FPGA can execute steps sequentially. I am very confused about how sequential assignments, functions and similar are being generated in an FPGA, so can anyone throw some light on this topic?
process(d, clk)
begin
if(rising_edge(clk)) then
q <= d;
else
q <= q;
end if;
end process;
This is just code for a simple D-Latch, but how will this be implemented in an FPGA?
It is not "executed" sequentially as such - but the synthesizer interprets the code sequentially, and creates the hardware design to fit such an interpretation.
For instance, if you assign a value to a signal twice during a clocked process, the first assignment is simply ignored, while the second takes effect (remember that a signal is only assigned at the end of a process statement, not immediately):
signal a : UNSIGNED(3 downto 0) := (others => '0');
(...)
process(clk)
begin
if(rising_edge(clk)) then
a <= a - 1;
a <= a + 1;
end if;
end process;
The above process will always increment a by 1. Similarly, if you have the second assignment inside an if statement, the synthesizer will simply create two paths for a - a decrement for when the if statement is not fullfilled, and an increment for when it is.
If you use variables, the idea is the same - although intermediate values are used, as variables take on their new value immediately.
But it all boils down to that the synthesizer does all the "magic" of interpreting your process in a sequential way, then generating hardware that does what you have described.
Your example basically describes a d-flip-flop (the Xilinx FPGA tools iirc distinguish latches and flip-flops in that flip-flops are edge-sensitive, and latches are level-sensitive), although in a different way than typically recommended.
You can basically write the same code as:
process(clk)
begin
if(rising_edge(clk)) then
q <= d;
end if;
end process;
It will automatically keep its value in the other cases. This will be implemented as a flip-flop inside the FPGA. Most FPGAs consist of blocks of look-up tables and flip-flops, to which quite a lot of different hardware can be mapped. The above code will simply by-pass the look-up table, and just use the flip-flop of one of the blocks.
You can learn more about the internal workings by having a look at the datasheet for your particular FPGA. For Spartan3-series FPGAs for instance, have a look at page 24 of the Xilinx Spartan3 FPGA Family Data Sheet