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.
Related
Below is a counter that is designed to represent an 8 bit binary number with 8 LEDs, it is being simulated using a test bench, however when running the simulation the output simply shows UU for the led.
Here is the main entity that I wish to test:
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_unsigned.all;
entity Lab_3_Source_File is
generic(N_BITS : integer := 8);
port(
btnd : in STD_LOGIC ;
clk : in STD_LOGIC;
led : out STD_LOGIC_VECTOR(7 downto 0)
);
end Lab_3_Source_File;
architecture counter of Lab_3_Source_File is
signal count: STD_LOGIC_VECTOR(7 downto 0);
begin
process(clk, btnd)
begin
if btnd = '1' then
count <= (others => '0');
elsif rising_edge(clk) then
count <= count + 1;
end if;
end process;
led <= count;
end counter;
Here is the test bench that I have tried to map to the main entity:
use IEEE.STD_LOGIC_1164.ALL;
entity Count_TestBench is
end Count_TestBench;
architecture Behavioral of Count_TestBench is
signal btnd, clk : STD_LOGIC;
signal led : STD_LOGIC_VECTOR(7 downto 0);
begin
UUT : entity work.Lab_3_Source_File port map (btnd => btnd,clk => clk,led => led);
process
begin
btnd<='1';
wait for 1 ns;
btnd<='0';
led<= (others => '0');
for i in 1 to 100 loop
clk<='1';
wait for 10 ns;
clk<='0';
wait for 10 ns;
led<=led;
end loop;
end process;
end Behavioral;
Please could somebody help me understand how to enable the simulation to display the led output incrementing?
EDIT:
Set btnd to 1 with a 1ns wait in the test bench to initialise the led, following the answer from mkrieger1, the led output is still at U following this change.
count is not initialized inside Lab_3_Source_File until btnd is set to '1', which it isn't in the testbench.
Since the led output is driven by count, it is also uninitialized. The uninitialized value of the led output of Lab_3_Source_File is then assigned to the led signal in the testbench.
So, to fix this, you need to set btnd to '1' once for a non-zero duration in the testbench, before setting it to '0' again (otherwise led is held at "00000000" constantly).
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.
--
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity D_flip_flop is
port (
D : in STD_LOGIC;
Q : inout STD_LOGIC;
Q_tonos : out STD_LOGIC;
CLK : in STD_LOGIC;
RST : in STD_LOGIC
);
end D_flip_flop;
architecture Behavioral of D_flip_flop is
begin
process_flip_flip: process
begin
wait until CLK'EVENT AND CLK = '1';
if(RST='1') then
Q <= '0';
else
Q <= D;
end if;
Q_tonos <= not Q;
end process process_flip_flip;
end Behavioral;
-------------------------
--testbench
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
ENTITY test_flip_flop IS
END test_flip_flop;
ARCHITECTURE tb OF test_flip_flop IS
COMPONENT D_flip_flop
PORT(
D : IN std_logic;
Q : INout std_logic;
Q_tonos : OUT std_logic;
CLK : IN std_logic;
RST : IN std_logic
);
END COMPONENT;
signal D : std_logic ;
signal CLK : std_logic ;
signal RST : std_logic ;
signal Q : std_logic;
signal Q_tonos : std_logic;
constant CLK_period : time := 10 ns;
signal stopClk : boolean;
BEGIN
-- Instantiate the Unit Under Test (UUT)
dut: D_flip_flop PORT MAP (
D => D,
Q => Q,
Q_tonos => Q_tonos,
CLK => CLK,
RST => RST
);
CLK_process :process
begin
while not stopClk loop
CLK <= '0';
wait for CLK_period/2;
CLK <= '1';
wait for CLK_period/2;
end loop;
wait;
end process CLK_process;
-- Stimulus process
stim_proc: process
begin
-- insert stimulus here
D <= '0';
RST <= '1';
wait for 100 ns;
D <= '0';
RST <= '0';
wait for 100 ns;
D <= '1';
RST <= '0';
wait for 100 ns;
D <= '1';
RST <= '0';
wait for 100 ns;
wait;
end process;
END;
You are missing one line in your testbench, I think:
D <= '1';
RST <= '0';
wait for 100 ns;
stopClk <= TRUE; -- add this line
wait;
end process;
END;
http://www.edaplayground.com/x/56Mm
That way, when the test is finished, the clock stopClk signal turns off the clock generator and the simulation finishes. It finishes because it reaches a state called event starvation. Every time a line of code containing a signal assignment is executed, an event is added to the simulators event queue (its "to do list"). If you create a situation where no such lines continue to be executed, then the event queue becomes empty. This is event starvation. The simulator detects that and the simulation stops. (If you think about, what else could it do?)
Without this extra line, the simulation runs forever, because the clock generation process executes signal assignments forever, so the event queue is never empty.
Not really an answer, but: consider using if rising_edge(CLK) or maybe if CLK='1' and CLK'event instead of wait until. Not all synhtesis tools support that kind of code and anyway it's rare to see it in professional world ;)
p.s. stopClk signal is not driven (or was it?) Your TB clock is enably by that, yet I guess it remains 'u' for the whole simulation. Unless forced in the simulation.
What the cause of different delays of signals Q_VLD1 and Q_VLD2 in simulator?
Result of simulation. Is it expected behaviour of simulator or not?
I use Xilinx Isim.
There is the code and testbench for it:
entity assign_test is
port(CLK : in STD_LOGIC;
D_VLD : in STD_LOGIC;
Q_VLD1 : out STD_LOGIC;
Q_VLD2 : out STD_LOGIC
);
end assign_test;
architecture Behavioral of assign_test is
signal D_VLD_i : std_logic;
signal d_vld_dly1 : std_logic;
signal d_vld_dly2 : std_logic;
begin
D_VLD_i <= D_VLD;
process (clk) is
begin
if rising_edge(clk) then
d_vld_dly1 <= D_VLD;
d_vld_dly2 <= D_VLD_i;
end if;
end process ;
Q_VLD1 <= d_vld_dly1;
Q_VLD2 <= d_vld_dly2;
end Behavioral;
ENTITY tb_assign_test IS
END tb_assign_test;
ARCHITECTURE behavior OF tb_assign_test IS
COMPONENT assign_test
PORT(
CLK : IN std_logic;
D_VLD : IN std_logic;
Q_VLD1 : OUT std_logic;
Q_VLD2 : OUT std_logic
);
END COMPONENT;
--Inputs
signal CLK : std_logic := '0';
signal D_VLD : std_logic := '0';
--Outputs
signal Q_VLD1 : std_logic;
signal Q_VLD2 : std_logic;
constant CLK_period : time := 10 ns;
BEGIN
uut: assign_test PORT MAP (
CLK => CLK,
D_VLD => D_VLD,
Q_VLD1 => Q_VLD1,
Q_VLD2 => Q_VLD2
);
CLK_process :process
begin
CLK <= '0';
wait for CLK_period/2;
CLK <= '1';
wait for CLK_period/2;
end process;
stim_proc: process
begin
wait for 100 ns;
wait for 5 ns;
wait for CLK_period*10;
D_VLD <= '1';
wait for CLK_period*3;
D_VLD <= '0';
wait;
end process;
END;
So if you look at the internal signals in the assign_test module, based on simulation time only, it may look as in figure below (d_vld_dly* is before assign to Q_VLD*).
But the figure is misleading, since that figure does not show the VHDL concept of delta delay. If the waveform is expanded to show delta delays (using ModelSim in this case), it looks like below.
So this reveals that the D_VLD_i <= D_VLD; in the assign_test actually delays the D_VLD_i a delta delay, whereby the new value is not seen at the clock until next rising clock edge.
The reason for this problem, is that the test bench does not generate input data as a cause of the clock, which would make data one delta delay after the clock, but independently and at the same simulation time and same delta delay as the clock.
The test bench can be updated to generate data as a cause of the clock, if wait for clock is changed from:
wait for CLK_period*10;
to:
for i in 1 to 10 loop
wait until rising_edge(CLK);
end loop;
which will then give a waveform as:
So based on this, a rule for good test bench design is to generate stimuli the same way as generating data in synthesized modules, so the stimuli from the test bench is like data between modules in general, in order to get expected and reliable and test bench behavior.
I am trying to run a code that I have picked up online, but it somehow the testbench is failing to run the expected output on GHDL.
Architecture Code
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity clk200Hz is
Port (
clk_in : in STD_LOGIC;
reset : in STD_LOGIC;
clk_out: out STD_LOGIC
);
end clk200Hz;
architecture Behavioral of clk200Hz is
signal temporal: STD_LOGIC;
signal counter : integer range 0 to 124999 := 0;
begin
frequency_divider: process (reset, clk_in) begin
if (reset = '1') then
temporal <= '0';
counter <= 0;
elsif rising_edge(clk_in) then
if (counter = 124999) then
temporal <= NOT(temporal);
counter <= 0;
else
counter <= counter + 1;
end if;
end if;
end process;
clk_out <= temporal;
end Behavioral;
Test Bench:
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
ENTITY clk200Hz_tb IS
END clk200Hz_tb;
ARCHITECTURE behavior OF clk200Hz_tb IS
COMPONENT clk200Hz
PORT(
clk_in : IN std_logic;
reset : IN std_logic;
clk_out: OUT std_logic
);
END COMPONENT;
-- Inputs
signal clk_in : std_logic := '0';
signal reset : std_logic := '0';
-- Outputs
signal clk_out : std_logic;
constant clk_in_t : time := 20 ns;
BEGIN
-- Instance of unit under test.
uut: clk200Hz PORT MAP (
clk_in => clk_in,
reset => reset,
clk_out => clk_out
);
-- Clock definition.
entrada_process :process
begin
clk_in <= '0';
wait for clk_in_t / 2;
clk_in <= '1';
wait for clk_in_t / 2;
end process;
-- Processing.
stimuli: process
begin
reset <= '1'; -- Initial conditions.
wait for 100 ns;
reset <= '0'; -- Down to work!
wait;
end process;
END;
I expect a wave that would form a clock pulsing up and down, however that does not seem to be the case. I wonder what is wrong with the design.
I ran the following commands:
ghdl -s *.vhd
ghdl -a *.vhd
ghdl -e clk200Hz_tb
ghdl -r clk200Hz_tb --vcd=led.vcd
gtkwave led.vcd
and this is my output
but for clock out, I expect a up and down signal, not a signal of 0.
Thanks
I have fixed the problem, in my running command, I simply added ghdl -r clk200Hz_tb --vcd=led.vcd --stop-time=100ns.
ghdl -a clk200Hz_tb.vhdl
ghdl -e clk200Hz_tb
ghdl -r clk200Hz_tb --wave=clk200hz_tb.ghw --stop-time=500ns
Gave:
(clickable)