Unconditional WAIT statement's effect on processes in VHDL - vhdl

There is something I do not understand about VHDL processes ending with an unconditional wait statement. To illustrate my problem, I need to compare the 2 following snipets :
snipet 1 :
library ieee;
use ieee.std_logic_1164.all;
entity foo is
end entity;
architecture sim of foo is
signal clk : std_logic := '0';
signal s : std_logic;
begin
clk <= not clk after 10 ns;
-- driver1
s <= '0';
-- driver2
process (clk) is
begin
s <= clk;
end process;
end architecture;
There is a double assignment for signal s: Driver1 drives the signal s to '0' while driver2 alternatively drives it to '0' and '1'. As we can see on the waveform graph, when clk is '0', the resulting s is '0' (green segments) but when clk is '1', the resulting s is 'X' (red segments).
=> I understand this behaviour, no problem with that one.
If I modify slightly this code by changing driver1 into a process ended with an unconditional wait instruction :
snipet2 :
library ieee;
use ieee.std_logic_1164.all;
entity foo is
end entity;
architecture sim of foo is
signal clk : std_logic := '0';
signal s : std_logic;
begin
clk <= not clk after 10 ns;
-- driver1
-- s <= '0';
process
begin
s <= '0';
wait;
end process;
-- driver2
process (clk) is
begin
s <= clk;
end process;
end architecture;
Surprisingly, for me, the snipet 2 produces the same waveform as the snipet 1. My understanding is that the instructions inside a process with a final "unconditional" wait statement will stop forever, meaning that their code will be inactive after the first execution run. But if this is truly the case, I would expect that driver1 in snipet 2 is inactive after its first run, and that from that point driver2 remains the only active driver of signal s, always assigning clk's alternative '1's and '0's to it.
Why isn't it the case?

When you assign a signal in a process, a driver is created for that signal from the moment it assigned until the end of simulation. So here, both code snippets are functionally equivalent, you create driver1 from time 0 and driver2 from the first clock.

Related

My VHDL code compile but the RTL Simulation doesn't run

I am somewhat new to VHDL and am trying to create a simple code for a Flip Flop D. My code compiles correctly, however when I run my Testbench tb_FlipFlopD in ModelSim Altera, the program opens but there's no wave, and I don't have the option to add it either.
The bug is problaby in my Testbench.
My Top-level identity code FlipFlopD:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity FlipFlopD is
port( clock: in std_logic;
D: in std_logic;
Q: out std_logic
);
end FlipFlopD;
architecture RTL of FlipFlopD is
begin
Q <= D when clock = '1' and clock'event;
end RTL;
My Testbench tb_FlipFlopD:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity tb_FlipFlopD is
end tb_FlipFlopD;
architecture teste of tb_FlipFlopD is
component FlipFlopD is
port (
clock : in std_logic;
D : in std_logic;
Q : out std_logic
);
end component;
signal I: std_logic;
signal O: std_logic;
signal C: std_logic := '0';
constant clk_period : time := 1 ns;
begin
instancia_FlipFlopD: FlipFlopD port map( D => I, Q => O, clock => C);
I <= '0', '1' after 1 ns, '1' after 2 ns, '0' after 3 ns, '1' after 4 ns;
clk_process : process
begin
C <= '0';
wait for clk_period/2;
C <= '1';
wait for clk_period/2;
end process;
end teste;
Your problem is that you simulation runs, but never stops; it just keeps on running forever.
Any VHDL (or Verilog) simulation will keep running if there is still stuff to do. This process:
clk_process : process
begin
C <= '0';
wait for clk_period/2;
C <= '1';
wait for clk_period/2;
end process;
generates an event (a change) on the the signal C every clk_period/2. Forever. To cure this, you need to put something in to stop this, eg:
clk_process : process
begin
while not STOP loop
C <= '0';
wait for clk_period/2;
C <= '1';
wait for clk_period/2;
end loop;
wait;
end process;
The wait; at the end of the process, waits forever. Signal STOP is a boolean:
signal STOP : boolean := false;
Then you need something like this to drive signal STOP:
STOP <= false, true after 10 ns;

Quartus II : simple counter but weird behaviour

First of all I'm sorry to bother you guys with my very noob question, but I can't find any sense to what's happening with my (ModelSim simulated) circuit.
Here's my code, simple as can be :
LIBRARY ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
ENTITY Counter IS
PORT(
enable : in std_logic;
clk : in std_logic;
count : out integer range 0 to 255);
END Counter;
ARCHITECTURE LogicFunction OF Counter IS
signal count_i : integer range 0 to 255;
begin
cnt : process(clk, enable, count_i)
begin
count <= count_i;
if (enable = '0') then
count_i <= 0;
else
count_i <= count_i + 1;
end if;
end process;
end LogicFunction;
My problem is : when I perform a timing simulation with ModelSim, with a clock signal, "enabled" is first '0' and then '1', the output ("count") stays at zero all the time. I tried a lot of different things, like setting the "count" out as a vector, doing all sorts of casts, but it still stays the same.
The increment "count_i <= count_i + 1;" seems to be the problem : I tried to replace it with something like "count_i <= 55", and then the output changes (to "55" in the previous example).
I've seen the exact same increment in the code on that webpage for example :
http://surf-vhdl.com/how-to-connect-serial-adc-fpga/
I've created a project, simulated it and... it works ! I really don't get what the guy did that I didn't, excepted for a bunch of "if" that I don't need in my code.
Any help would be greatly appreciated, I've spent like 3 hours of trial and errors...
Thanx in advance !
In addition to not using a clock edge to increment i_count you're using enable as a clear because it's both in the sensitivity list and encountered first in an if statement condition.
library ieee;
use ieee.std_logic_1164.all;
-- use ieee.numeric_std.all;
entity counter is
port(
enable : in std_logic;
clk : in std_logic;
count : out integer range 0 to 255);
end counter;
architecture logicfunction of counter is
signal count_i : integer range 0 to 255;
begin
cnt : process (clk) -- (clk, enable, count_i)
begin
-- count <= count_i; -- MOVED
-- if (enable = '0') then -- REWRITTEN
-- count_i <= 0;
-- else
-- count_i <= count_i + 1;
-- end if;
if rising_edge(clk) then
if enable = '1' then
count_i <= count_i + 1;
end if;
end if;
end process;
count <= count_i; -- MOVED TO HERE
end architecture logicfunction;
Your code is modified to using the rising edge of clk and require enable = '1' before i_count increment. The superfluous use clause referencing package numeric_std has been commented out. The only numeric operation you're performing is on an integer and those operators are predefined in package standard.
Note the replacement if statement doesn't surround it's condition with parentheses. This isn't a programming language and they aren't needed.
The count assignment is moved to a concurrent signal assignment. This removes the need of having i_count in the sensitivity list just to update count.
Throw in a testbench to complete a Miminal Complete and Verifiable Example:
library ieee;
use ieee.std_logic_1164.all;
entity counter_tb is
end entity;
architecture foo of counter_tb is
signal enable: std_logic := '0';
signal clk: std_logic := '0';
signal count: integer range 0 to 255;
begin
DUT:
entity work.counter
port map (
enable => enable,
clk => clk,
count => count
);
CLOCK:
process
begin
wait for 5 ns; -- 1/2 clock period
clk <= not clk;
if now > 540 ns then
wait;
end if;
end process;
STIMULUS:
process
begin
wait for 30 ns;
enable <= '1';
wait for 60 ns;
enable <= '0';
wait for 30 ns;
enable <= '1';
wait;
end process;
end architecture;
And that gives:
Which shows that the counter doesn't counter when enable is '0' nor does enable = '0' reset the value of i_count.
The Quartus II Handbook Volume 1 Design and Synthesis doesn't give an example using a clock edge and an enable without an asynchronous clear or load signal.
The secret here is anything inside the if statement condition specified using a clock edge will be synchronous to the clock. Any condition outside will be asynchronous.
The form of synthesis eligible sequential logic is derived from the now withdrawn IEEE Std 1076.6-2004 IEEE Standard for VHDL Register
Transfer Level (RTL) Synthesis. Using those behavioral descriptions guarantees you can produce hardware through synthesis that matches simulation.

ISIM signal assignment delay

I expected signal 'delay' to be one clock cycle late wrt to the entities' port 'input', but ISIM shows no phase shift.
I thought there is always is a delay between signal assignment and actual value (when the process suspends), but I don't seee it here.
Why is this?
Code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity test is
Port ( clk: in std_logic;
input: in std_logic
);
end test;
architecture Behavioral of test is
signal delay: std_logic:= '0';
begin
proc1: process(clk)
begin
if(rising_edge(clk)) then
delay <= input; -- ISIM shows no delay between them
end if;
end process;
end Behavioral;
Testbench:
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
ENTITY tb_testbench_test IS
END tb_testbench_test;
ARCHITECTURE behavior OF tb_testbench_test IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT test
PORT(
clk: in std_logic;
input: in std_logic
);
END COMPONENT;
--Inputs
signal clk: std_logic := '0';
signal input: std_logic := '0';
-- Clock period definitions
constant clk_period : time := 10 ns;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: test PORT MAP (
clk => clk,
input => input
);
-- Clock process definitions
clk_process :process
begin
clk <= '0';
wait for clk_period/2;
clk <= '1';
wait for clk_period/2;
end process;
-- Stimulus process
stim_proc: process
begin
wait for clk_period * 9.5;
input <= '1';
wait for clk_period;
input <= '0';
wait;
end process;
end;
Your test bench describes clk and input going high at the same time. You then have a process in your entity that is looking for a rising_edge of clk. Therefore, when your process runs, and asks 'was there a rising edge of the clock?', if the answer to this is 'yes', i.e. the clock signal had just become '1', then the state of the input must also be '1', because the two signals changed at the same time. The delay signal then takes this new input, giving the result you see.
A more realistic scenario would be a change of the input being caused by a rising edge of clk. You can easily simulate this by modifying your stimulus process:
stim_proc: process
begin
wait for clk_period * 9.5;
wait until clk = '1'; -- Sit here until we have seen a rising edge of `clk`
input <= '1'; -- This assignment now happens *after* the clock edge
wait until clk = '1';
input <= '0';
wait;
end process;
The delay between a signal assignment and the appearance of its value is ... one delta cycle. And the time taken by one delta cycle is 0 fS.
What your testbench represents is a race condition whereby you present the input signal and the clock signal at exactly the same time - i.e. in the same delta cycle.
In real hardware, what would happen would be a coin-toss whether the input was seen by this clock edge or the next, or would be some intermediate value when the clock edge happened, raising the possibility of metastable operation.
The simulation has accidentally alerted you to the possibility of such mis-operation.
If you delay the data signal by even one delta cycle (as is guaranteed to happen if it was the output from a previous clocked process) such as a concurrent signal assignment outside the process, you will eliminate the timing hazard and see the delay you expect.

Modelsim fatal error when assigning constant value to signal in procedure

There has been years since i have written any VHDL, so the answer may be obvious.
I am making a testbench to a module i have made, and it uses this procedure to write to a register on UUT:
procedure write_data_proc (
constant data_value : in std_logic_vector;
signal write_en : out std_logic;
signal data_in : out std_logic_vector;
signal clk : in std_logic
) is
begin
wait until falling_edge(clk);
write_en <= '1';
data_in <= data_value;
wait until falling_edge(clk);
write_en <= '0';
end procedure;
It is called from this main stimulation process:
stim_process: process
begin
mask <= "0000000011111111";
reset <= '1';
wait for 2 ns;
reset <= '0';
wait for 3 ns;
write_data_proc("0000000011110000",write_en,data_in,clk);
write_data_proc("0000000011001100",write_en, data_in,clk);
write_data_proc("0000000010001001",write_en,data_in,clk);
read_bytes(3,8,data_read, data_read_master, clk);
end process;
Modelsim gives me a "FATAL ERROR" on the following line in the procedure:
data_in <= data_value;
I have googled my head off, and i find very little to help me on my way. I hope some of you guys can help me understand what is going on here. If more information is needed, i would be happy to provide more code.
Thanks a lot!
That's not an MCVE.
It's just a couple of code fragments, missing a lot of vitally important stuff.
Like declarations.
This is an MCVE.
library ieee;
use ieee.std_logic_1164.all;
entity const_value is
end const_value;
architecture test of const_value is
signal mask,data_in : std_logic_vector(15 downto 0);
signal reset, clk, write_en : std_logic;
procedure write_data_proc (
constant data_value : in std_logic_vector;
signal write_en : out std_logic;
signal data_in : out std_logic_vector;
signal clk : in std_logic
) is
begin
wait until falling_edge(clk);
write_en <= '1';
data_in <= data_value;
wait until falling_edge(clk);
write_en <= '0';
end procedure;
begin
stim_process: process
begin
mask <= "0000000011111111";
reset <= '1';
wait for 2 ns;
reset <= '0';
wait for 3 ns;
write_data_proc("0000000011110000",write_en,data_in,clk);
write_data_proc("0000000011001100",write_en, data_in,clk);
write_data_proc("0000000010001001",write_en,data_in,clk);
-- read_bytes(3,8,data_read, data_read_master, clk);
end process;
end test;
Now when I test it, it compiles, elaborates and simulates without fatal errors.
ghdl -a const_value.vhd
ghdl -e const_value
ghdl -r const_value
Or indeed, without any output at all. It would be a good idea to make the testbench self-checking, by adding assert statements in the stimulus process (or another process) testing that the outputs acre the expected values.
Given the exact same MCVE above, what do you get in Modelsim?
If you get the same result as I do, then tell us your real problem : and this time, make an MCVE of it.

how to avoid delay in the output of simple process statement in VHDL

i am a beginner in VHDL. i want ot know why there is a delay of one cycle in the following code.and how to avoid it..at the same time in verilog the statement always #(posedge clk) dont have any delay.. how to do the same in VHDL
library IEEE;
use IEEE.std_logic_1164.all;
-- entity
entity t_ff_s is
port ( T,S,CLK : in std_logic;
Q : out std_logic);
end t_ff_s;
-- entity
architecture my_t_ff_s of t_ff_s is
signal t_tmp : std_logic; -- intermediate signal declaration
begin
tff: process (S,rising_edge(clk))
begin
if (S = '0') then
t_tmp <= '1';
--elsif (rising_edge(CLK)) then
else
t_tmp <= T XOR t_tmp; -- temp output assignment
end if;
end process tff;
Q <= t_tmp; -- final output assignment
end my_t_ff_s;
Sensitivity lists in VHDL don't take an edge specification like in Verilog. VHDL is more flexible in that you can freely use the 'event signal attribute anywhere within a process to implement edge triggered behavior. You can mix level and edge sensitive logic without resorting to split blocks/processes or hacks like negedge for resets. Function calls like rising_edge(clk) (which implements a test for clk'event) are not permitted in a sensitivity list. It only contains signal names. Your code won't compile as is.
If some other syntactically correct version of your code compiles cleanly, the delays you see are artifacts of the simulation model or having a broken sensitivity list. If you want a synchronous clock driven process then you only need the clock signal and possibly an asynchronous reset in the sensitivity list.
Consider the following process:
tff: process(S, clk)
begin
if S = '0' then -- Asynchronous reset (level sensitive)
t_tmp <= '1';
elsif rising_edge(clk) then -- Synchronous logic (edge sensitive)
t_tmp <= T xor t_tmp;
end if;
end process;
Q <= t_tmp;
This process executes when an event occurs on S or clk. If S is '0' then the reset condition is executed with priority over the elsif clause (clk is a don't-care). The assignment to t_tmp takes effect on the next delta cycle which is still the same as the current simulation time. Otherwise, if rising_edge(clk) evaluates to true then an event occurred on clk and it's state changed from '0' (or 'L') to '1' (or 'H') indicating that the event was a rising edge. The synchronous assignment takes place and the new xored t_tmp takes effect on the next delta cycle. Changes in T don't cause the process to execute since it isn't (and shouldn't be) in the sensitivity list.
Because there is no unconditional else clause the t_tmp signal retains its last assigned value if both of the two if conditions are false. It will change the next time there is an event on S or clk that causes a new assignment to t_tmp. This will either be the next clock edge or a re-application of asynchronous reset.
The assignment to Q is continuous and is effectively the same as a process with t_tmp in its sensitivity list. As a consequence, the assignment to Q takes place a delta cycle after events on t_tmp which is two delta cycles after the rising edge. If Q is feeding into logic that updates earlier than the second delta cycle of an edge, it will appear to take an extra clock cycle for it to propagate.
The behavior surrounding delta cycles can sometimes create confusing results when inspecting waveforms. You may have a rising edge that should capture a data input that appears to transition simultaneously on the same time step when, in fact, the data is transitioning on a later delta cycle and will only be captured on the next clock edge.
Similarly, if you construct a simple gated clock without any time delay, its edges will occur at the same time but on later delta cycles than the ungated version of the clock. Data driven from the "earlier" ungated clock will be captured by the gated logic a clock cycle earlier than expected as a result. Data driven the other direction will appear to have an unexpected delay by a clock cycle.
It isn't clear what is causing the problem you see without more information on how you're driving the S, T, and clk signals but it is likely connected to the delta cycle behavior of the simulation engine in some way.
The problem
A little more succinctly than Kevin, rising_edge is an expression and not a signal, a sensitivity list requires a named signal, a transaction on which you resume execution of a suspended process. Put the elsif back in and have only S and clk in the sensitivity list.
Note that because t_tmp isn't in the sensitivity list, you won't see Q follow t_tmp until the next clock event causing the delay you noted.
The fixed syntax process:
tff: process (S,clk) -- was (S, risingedge(CLK)), a syntax error)
begin
if (S = '0') then
t_tmp <= '1';
elsif (rising_edge(CLK)) then -- put back
-- else
t_tmp <= T XOR t_tmp; -- temp output assignment
end if;
Q <= t_tmp; -- final output assignment
end process tff;
Which shows the delay between t_tmp and Q:
(clickable)
Fix it by making Q a concurrent signal assignment
To cure the half clock delay you could make the assignment to Q a concurrent signal assignment statement (move it outside of the process).
tff:
process (S, clk)
begin
if S = '0' then
t_tmp <= '1';
elsif rising_edge(clk) then
t_tmp <= T xor t_tmp;
end if;
end process;
Q <= t_tmp; -- concurrent signal assignment
Which gives:
(clickable)
And you can see above that t_tmp and Q are now in phase.
Fix it by making t_tmp a variable
You could also declare t_tmp as a variable in process dff instead of a signal and switching assignments to it as variable assignments will also cure the one clock delay between t_tmp and Q.
tff:
process (S, clk)
variable t_tmp: std_logic;
begin
if S = '0' then
t_tmp := '1';
elsif rising_edge(clk) then
t_tmp := T xor t_tmp;
end if;
Q <= t_tmp;
end process;
Which shows:
(clickable)
And ghdl using gtkwave doesn't output variables or show delta cycles. You can see Q occurs on the rising edge of the clock.
Making t_tmp a variable also has the effect of eliminating a delta cycle between a transaction on t_tmp and a transaction on Q.
Eliminating delta cycles makes your model execute faster (while occurring at the current simulation time). Signal assignments don't take effect while any process is executing and variable assignments take effect immediately.
Fix it by adding t_tmp to the sensitivity list
And alternatively you could just add t_tmp to the sensitivity list (along with S and clk).
tff:
process (S, clk, t_tmp)
begin
if S = '0' then
t_tmp <= '1';
elsif rising_edge(clk) then
t_tmp <= T xor t_tmp;
end if;
Q <= t_tmp;
end process;
(clickable)
And this is slower than all the rest of the fixes because the if statement is executed each time t_tmp has an event as well as S or CLK. rising_edge is a function call which dynamically elaborates it's interface list, a significant simulator performance penalty particularly if you use a lot of these primitives.
These were done with a test bench:
library IEEE;
use IEEE.std_logic_1164.all;
-- entity
entity t_ff_s is
port ( T,S,CLK : in std_logic;
Q : out std_logic);
end entity t_ff_s;
architecture my_t_ff_s of t_ff_s is
signal t_tmp : std_logic; -- intermediate signal declaration
begin
tff: process (S,clk) -- was (S, risingedge(CLK)), a syntax error)
begin
if (S = '0') then
t_tmp <= '1';
elsif (rising_edge(CLK)) then -- put back
-- else
t_tmp <= T XOR t_tmp; -- temp output assignment
end if;
Q <= t_tmp; -- final output assignment
end process tff;
end my_t_ff_s;
architecture foe of t_ff_s is
signal t_tmp: std_logic;
begin
tff:
process (S, clk)
begin
if S = '0' then
t_tmp <= '1';
elsif rising_edge(clk) then
t_tmp <= T xor t_tmp;
end if;
end process;
Q <= t_tmp; -- concurrent signal assignment
end architecture;
architecture fie of t_ff_s is
begin
tff:
process (S, clk)
variable t_tmp: std_logic;
begin
if S = '0' then
t_tmp := '1';
elsif rising_edge(clk) then
t_tmp := T xor t_tmp;
end if;
Q <= t_tmp;
end process;
end architecture;
architecture fee of t_ff_s is
signal t_tmp: std_logic;
begin
tff:
process (S, clk, t_tmp)
begin
if S = '0' then
t_tmp <= '1';
elsif rising_edge(clk) then
t_tmp <= T xor t_tmp;
end if;
Q <= t_tmp;
end process;
end architecture;
library ieee;
use ieee.std_logic_1164.all;
entity test_tff is
end entity;
architecture foo of test_tff is
signal CLK: std_logic := '0';
signal T: std_logic := '0';
signal S: std_logic := '0';
signal Q: std_logic;
component t_ff_s is
port (
signal CLK: in std_logic;
signal T: in std_logic;
signal S: in std_logic;
signal Q: out std_logic
);
end component;
begin
DUT:
t_ff_s
port map (
T => T,
S => S,
CLK => CLK,
Q => Q
);
CLOCK:
process
begin
wait for 10 ns;
CLK <= not CLK;
if Now > 250 ns then
wait;
end if;
end process;
SET:
process
begin
S <= '0';
wait for 20 ns;
S <= '1';
wait;
end process;
TOGGLE:
process
begin
wait for 20 ns;
T <= '1';
wait for 60 ns;
T <= '0';
wait for 40 ns;
T <= '1';
wait;
end process;
end architecture;
configuration my_t_ff_s_config of test_tff is
for foo
for DUT: t_ff_s
use entity work.t_ff_s(my_t_ff_s);
end for;
end for;
end configuration;
configuration concurrent_config of test_tff is
for foo
for DUT: t_ff_s
use entity work.t_ff_s(foe);
end for;
end for;
end configuration;
configuration variable_config of test_tff is
for foo
for DUT: t_ff_s
use entity work.t_ff_s(fie);
end for;
end for;
end configuration;
configuration sensitivity_config of test_tff is
for foo
for DUT: t_ff_s
use entity work.t_ff_s(fee);
end for;
end for;
end configuration;
note the use of configuration
Using VHDL's configuration declarations to allow the use of multiple architectures. (my_t_ff_s - the original, foe - with concurrent assignment to Q, fie - with t_tmp as a variable and fee - with t_tmp in the sensitivity list).
And amazingly enough ghdl's analyzer was quite helpful getting the configuration declarations syntax right. Once you get the first one, the others are easy.
We tend to get rusty using configuration, it wasn't generally supported historically by synthesis tools. But then again, this is simulation for verification.
And for those with ghdl and gtkwave this is how it was done:
ghdl -a t_ff.vhdl
ghdl -e my_t_ff_s_config
ghdl -e concurrent_config
ghdl -e concurrent_config
ghdl -e sensitivity_config
ghdl -r my_t_ff_s_config --wave=test_tff_my_t_ff_s.ghw
ghdl -r concurrent_config --wave=test_tff_foe.ghw
ghdl -r variable_config --wave=test_tff_fie.ghw
ghdl -r sensitivity_config --wave=test_tff_fee.ghw
GHW is ghdl's native waveform dump file format, understood by gtkwave.
In gtkwave:
open t_ff_s.gtkw (reads in test_tff_my_t_ff_s.ghw)
(otherwise read in test_tff_my_t_ff_s.ghw and add signals to
waveform display, format the window, save save file to t_ff_s.gtkw)
new tab open test_tff_foe.ghw
read save file open t_ff_s.gtkw
new tab open test_tff_fie.ghw
read save file open t_ff_s.gtkw
new tab open test_tff_fee.ghw
read save file open t_ff_s.gtkw
Note ghdl doesn't save variable state or delta cycles, t_tmp won't show up in the waveform for test_ff_fie.ghw.

Resources