What is needed to make a wait statement within a process with a sensitivity list - vhdl

I would like to have a process in paralel with a process that receives filter (code bellow). This filter will change if I have 16 bits in data_to_memory signal then I will in the other process store this in a variable and perform some filter calculations. I think that my code is correct but still gives me the error: A wait statement is illegal for a process with a sensitivity list.
I have this two process in a file and my testbench in a different file.
process(bits_received)
begin
if rising_edge(bits_received) then
bits_data_rec(7 downto 0)<=data_in;
filter<='0';
wait until rising_edge(bits_received);
data_to_memory<=bits_data_rec&data_in;
filter<='1';
wait for clock_period;
filter<='0';
end if;
end process;
the process in my testbench:
file_open(file_pointer,"inputs.txt",READ_MODE);
file_open(file_RESULTS,"target.txt",WRITE_MODE);
reset<='1';
wait for clock_period/2;
reset<='0';
wait for clock_period/2;
while not endfile(file_pointer) loop
readline(file_pointer, line_num);
read(line_num, data);
data_in<=data(7 downto 0);
bits_received<='1';
wait for clock_period;
bits_received<='0';
data_in<=data(15 downto 8);
bits_received<='1';
wait for clock_period;
bits_received<='0';
wait for clock_period;
WRITE(v_OLINE,out_filter);
writeline(file_RESULTS, v_OLINE);
wait for clock_period;
wait for clock_period;
end loop;
Is my testbench affecting the process(bits_received)?

Related

How do I add the bits of a vector and at the same time save the value in a vector signal? I use google translator**

I am trying to know if the amount of "1" in a std_logic_vector is an odd or even number. For that I am trying to use an "if" statement along with a counter, but I don't get the expected result.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.std_logic_unsigned.all;
entity prueba2 is
port (
entrada: in std_logic_vector(0 to 10)
);
end prueba2;
architecture Behavioral of prueba2 is
signal bit1: std_logic_vector(0 to 3):= (others => '0');
begin
prueba: process(entrada)
--variable suma: unsigned(0 to 2):= (others => '0');
begin
for i in 0 to 10 loop
if (entrada(i)= '1') then
bit1 <= bit1+1;
end if;
end loop;
end process;
end Behavioral;
I am not getting errors in the syntax, but for example, by entering a vector "1111111111" I receive as output in the simulation, using ISE design Suite, the value "0001" instead of "1010". I appreciate your corrections and code suggestions.
See IEEE Std 1076-2008 10.5.2.2 Executing a simple assignment statement, 14.7.3.4 Simulation cycle and 14.7.3.4 Signal update.
Signals aren't updated immediately. The current simulation cycle isn't complete until every process sensitive to an event has executed and potentially scheduled signal updates and subsequently suspended. Simulation time is advanced to the time the next signal update is scheduled. Signals are updated at the beginning of a simulation cycle before any suspended processes resume due to a signal event.
Processes both suspend and resume executing wait statements (see 10.2 Wait statement). A process statement (11.3) with a sensitivity list has an implicit wait statement as the last statement with it's sensitivity list having the contents of the process sensitivity list.
The signal bit1 won't update while the loop is executing, there is no implicit or explicit wait statement causing the process to suspend.
To solve the issue use a variable:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.std_logic_unsigned.all; -- arithmetic for std_logic_vector
entity prueba2 is
port (
entrada: in std_logic_vector(0 to 10) := (others => '1')
);
end entity prueba2;
architecture behavioral of prueba2 is
signal bit1: std_logic_vector(0 to 3):= (others => '0');
function to_string (inp: std_logic_vector) return string is
variable image_str: string (1 to inp'length);
alias input_str: std_logic_vector (1 to inp'length) is inp;
begin
for i in input_str'range loop
image_str(i) := character'VALUE(std_ulogic'IMAGE(input_str(i)));
end loop;
return image_str;
end function;
begin
prueba:
process (entrada) -- sensitivity list implies wait as final statement
-- variable suma: unsigned(0 to 2):= (others => '0');
variable suma: std_logic_vector(0 to 3);
begin
suma := (others => '0'); -- start at 0 every time
for i in entrada'range loop
if entrada(i) = '1' then
-- bit1 <= bit1+1 -- signals don't update until the beginning
-- of the next simulation cycle (at the soonest)
suma := suma + 1; -- variables assignment is immediate
end if;
end loop;
report "bit1 will be assigned " & to_string(suma);
bit1 <= suma; -- both the same length processes communicate with signals
-- wait on entrada; -- implicit wait statement, process suspends
end process;
end architecture behavioral;
You can see the variable has the same length as bit1. That's required, you input entrada has a length of 11 which requires a 4 bit value to accumulate the number of '1's.
There are some embellishments for testing. Some simulators will allow you to simulate a top level with ports as long as inputs have default values or can be forced. Here entrada is supplied with all '1's. The to_string function is provided in revision -2008 of the standard, also provided here for compatibility with earlier revisions. The report statement tells us the value of suma that will be assigned to bit1.
When the design unit is analyzed and elaborated (compiled) then run:
ghdl -a --ieee=synopsys -fexplicit prueba2.vhdl
ghdl -e --ieee=synopsys -fexplicit prueba2
ghdl -r prueba2
prueba2.vhdl:37:9:#0ms:(report note): bit1 will be assigned 1011
The loop has successfully counted all the '1's, and bit1 will have an update scheduled with the same simulation time (here 0 ms). The simulator will execute a follow on simulation cycle (a delta cycle) then without any further schedule signal updates scheduled in any projected output waveform (a queue) the simulation time will advance to TIME'HIGH and simulation will end.
When a simulation starts every process executes at least once following initialization. The event on bit1 will cause a signal value update but there are no processes in the stand alone example sensitive to bit1 and simulation will cease.
The default value on the input entrada, function to_string and the report statement can be removed, they are present for testing, a testbench not having been provided.

How to wait for a signal to be assigned new value within a process without using wait statement in vhdl

Basically I have to code a university project in vhdl. The main issues is that during a process I need assign a std_logic signal a '1' value so that a secondary process can start. I'm aware that the assignment to a signal is at the next clock cycle. But the problem is that I need to create a synthesizable hardware component so i can't really use wait statements. So here is the question: how can I wait a cycle of clock without using wait statements?
You need to use clocked process with a structure as follows. Process_2 will start on the clock cycle after start_signal is set.
process_1 : process(clock)
begin
if rising_edge(clock) then
start_signal <= '1';
end if;
end process;
process_2 : process(clock)
begin
if rising_edge(clock) then
if start_signal then
--do stuff
end if;
end if;
end process;

Not able to write the output of testbench to file

LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.NUMERIC_STD.ALL;
use IEEE.STD_LOGIC_ARITH.all;
use IEEE.STD_LOGIC_SIGNED.all;
use std.env.all;
USE IEEE.STD_LOGIC_TEXTIO.ALL;
USE STD.TEXTIO.ALL;
ENTITY tb_top IS
END tb_top;
ARCHITECTURE behavior OF tb_top IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT c4b
PORT(
clock : IN std_logic;
reset : IN std_logic;
count : OUT std_logic_vector(3 downto 0)
);
END COMPONENT;
--Inputs
signal clock : std_logic := '0';
signal reset : std_logic := '0';
--Outputs
signal count : STD_LOGIC_vector(3 downto 0) := "0000";
-- Clock period definitions
constant period : time := 100 ns;
-- Opening the file in write mode
file myfile : TEXT open write_mode is "fileio.txt";
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: c4b PORT MAP (
clock => clock,
reset => reset,
count => count
);
clock_process :process --providing clock to the counter
begin
clock <= '1';
wait for period/2;
clock <= '0';
wait for period/2;
end process;
write_process: process
variable abd: LINE;
--variable val1: integer;
begin
--val1 := CONV_INTEGER(count); --saw this in another program. even they converted a std_logic_vector to integer. didn't work!
loop --tried the infinite loop to check for the value 1111,
if (count = "1111") then --so that as soon as count reaches the value 1111,
finish (0); --it would stop, because i only need to write one entire sequence of the cycle to the file!!
else
write (abd, count);
writeline (myfile, abd);
end if;
end loop;
end process;
-- Stimulus process
stim_process: process
begin
reset <= '0'; --because it only works when reset is 0!
wait for 100 ns;
if (count = "1111") then --the value is written to the text file in a continuous loop,
finish (0); --which makes he file size go to as much as 1 GB
end if; --thus to stop it at exactly one cycle!
end process;
END;
So, basically what I want to do here is let the counter count up from 0000 too 1111 and then write the entire sequence to a text file. But I only wish to write exactly just one cycle. Hence I've added a loop to check the same. Here in the code above I'm not able to simulate the testbench properly. When I don't include the write_process part of the code, the simulation works perfectly, giving me exactly just one cycle! (Simulator result w/o write_process picture no 1). But when I try to use the write_process, not only does it not simulate (Simulator result after adding the write_process) picture no 2, it also writes UUUU continuously to the file, until I close the ISim, and file size goes to at least a few hundred MBs! Please help!
Without the entity/architecture for c4b no one can duplicate your error, it's visible however.
Note that the write process has no sensitivity list nor wait statement and a loop statement that won't exit unless external stimuli is provided - if (count = "1111") then ...
It doesn't seem proper to be using finish in both stim_process and write_process, there's no guarantee of execution order you can lose the last write (if you cure the write process defect).
You have four unused use clauses (numeric_std, std_logic_arith, std_logic_signed, std_logic_textio, with VHDL -2008).
So, basically what I want to do here is let the counter count up from 0000 too 1111 and then write the entire sequence to a text file.
There's nothing in your code that spools up output until your simulation finishes. Writing a line to file textio.txt occurs for events driving the write process.
Adding a model for c4b:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std_unsigned.all;
entity c4b is
port (
clock: in std_logic;
reset: in std_logic;
count: out std_logic_vector(3 downto 0)
);
end entity;
architecture foo of c4b is
begin
process (clock, reset)
begin
if reset = '1' then
count <= (others => '0');
elsif rising_edge (clock) then
count <= count + 1;
end if;
end process;
end architecture;
Removing unused use clauses (not strictly necessary):
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
-- USE IEEE.NUMERIC_STD.ALL;
-- IEEE.STD_LOGIC_ARITH.all;
-- use IEEE.STD_LOGIC_SIGNED.all;
use std.env.all;
-- USE IEEE.STD_LOGIC_TEXTIO.ALL;
USE STD.TEXTIO.ALL;
Changing the write_process to not endlessly loop:
-- write_process: process
-- variable abd: LINE;
-- --variable val1: integer;
-- begin
-- --val1 := CONV_INTEGER(count); --saw this in another program. even they converted a std_logic_vector to integer. didn't work!
-- loop --tried the infinite loop to check for the value 1111,
-- if (count = "1111") then --so that as soon as count reaches the value 1111,
-- finish (0); --it would stop, because i only need to write one entire sequence of the cycle to the file!!
-- else
-- write (abd, count);
-- writeline (myfile, abd);
-- end if;
-- end loop;
-- end process;
write_process:
process
variable abd: LINE;
begin
wait on count;
wait for 100 ns;
write (abd, count);
writeline (myfile, abd);
if count = "1111" then
finish (0);
elsif IS_X(count) then
report "count contains a metavalue and may not increment";
finish (-1);
end if;
end process;
The wait 100 ns; accommodates a reset to insure the counter can increment. It's possible to provide a design description of c4b that doesn't depend on reset. For purposes here, the supplied c4b doesn't do that. The wait 100 ns also provides the sample interval for count, which from the component declaration for c4b is free running, driven by clock events.
Changing the stim_process to not finish and wait instead:
-- -- Stimulus process
-- stim_process: process
-- begin
-- reset <= '0'; --because it only works when reset is 0!
-- wait for 100 ns;
-- if (count = "1111") then --the value is written to the text file in a continuous loop,
-- finish (0); --which makes he file size go to as much as 1 GB
-- end if; --thus to stop it at exactly one cycle!
-- end process;
-- END;
stim_process:
process
begin
reset <= '1';
wait for 100 ns;
reset <= '0';
wait for 100 ns;
wait;
end process;
Notice this also provides a reset interval seen on the following waveform.
And that gives us:
With the contents of textio.txt:
more fileio.txt
0000
0001
0010
0011
0100
0101
0110
0111
1000
1001
1010
1011
1100
1101
1110
1111
It's also possible to end simulation after detecting count is "1111" by stopping clock, avoiding the use of the finish procedure. Along with a write procedure supplied using the Synopsys package std_logic_texio:
procedure WRITE(L:inout LINE; VALUE:in STD_LOGIC_VECTOR;
This would allow the use of VHDL simulators complying to VHDL standard revisions earlier than -2008.

wait on an untimed signal in VHDL testbench

I have written a simulation process that sets or changes signals sequentially as required, I use wait statements normally to wait certain time intervals or wait on signal assignments, but that is true only when I know when a signal should be coming, an example:
reset <= '1';
write <= '0';
read <= '0';
wait for 25 ns;
reset <= '0';
chipselect <= '1';
wait until clk = '1';
but now I need to do something different, I have a signal that is normally 0, and I need to pause simulation stimulus whenever it is turned to 1. the signal however is not timed. meaning I cannot do it with a simple wait statement because the simulation will wait for it only at a certain time. I want that effect to happen at all times. how to do something like this?
Based on the description, I understand that you want to pause stimuli
generation based on a signal, so stimuli time is extended corresponding to the
time of the pause.
For this a signal with the active time (named active_time below) can be
created, and stimuli can then be generated based on this time. The active time
is only running when the active_stimuli is TRUE.
A support procedure (named active_wait_for below) corresponding to wait for
can then be created to wait for the requested amount of active time, for use in
the stimuli generation process.
Suggestion for code:
architecture syn of tb is
-- Active declarations
signal active_stimuli : boolean := TRUE;
constant ACTIVE_RESOLUTION : time := 1 ps;
signal active_time : time := 0 ps;
-- Wait procedure for active delay
procedure active_wait_for(delay : time) is
variable active_time_start_v : time;
begin
active_time_start_v := active_time;
if delay > 0 ps then
wait until active_time >= active_time_start_v + delay;
end if;
end procedure;
-- Stimuli signal
signal stimuli_a : std_logic;
signal stimuli_b : std_logic;
begin
-- Active time generation
process is
begin
wait for ACTIVE_RESOLUTION;
if active_stimuli then
active_time <= active_time + ACTIVE_RESOLUTION;
else -- Save execution time in loop by wait until
wait until active_stimuli;
end if;
end process;
-- Stimuli generation
process is
begin
stimuli_a <= '0';
stimuli_b <= '0';
wait until active_time >= 2 ns;
stimuli_a <= '1';
active_wait_for(3 ns);
stimuli_b <= '1';
wait;
end process;
...
Waveform showing operation is below:
Note that polarity is different than the signal in the question, but naming was
clearer with this polarity.
Some ideas for "pausing" a stimulus process on an interrupt-type signal:
Rewrite the stimulus as a clocked process (a state machine, for example) and use the interrupt as a clock enable. This may be a pain, though.
Maybe easier, whenever you wait, wait something like this:
wait until clk = '1';
if interrupt = '1' then
wait until interrupt = '0';
wait until clk = '1';
end if;
or if it's not a synchronous wait:
wait for 100 ns;
if interrupt = '1' then
wait until interrupt = '0';
end if;
You could, of course, write a procedure to make these easier. There may be simpler/more elegant ways to code those, but what I wrote should work.
Is this what you want:
process (start) begin
if rising_edge(start) then
-- Respond to start signal rising
end if;
end process;
There is nothing stopping your from writing another process in your testbench/simulation to wait for that other condition to happen. An example of when you might want to do this is when you are simply counting the number of events of a certain condition.
For example:
Signal_Waiter : process(interrupt)
begin
if rising_edge(interrupt) then
-- do stuff here such as increment a counter
end if;
end process;
Since this process is completely independent from your "stimulus" section of code, it is always ready to wakeup and process. In this case, it will wake up whenever the signal interrupt changes.
Be careful if you are driving stimulus signals from the separate process, because you can't have two processes driving the same signal. If you need feedback to your main control process, you could do that with a signal or a shared variable.

Breaking out of a procedure in VHDL

I am trying to figure out a way to break out of a procedure if some external event occurs. Let's say I have a procedure like this:
procedure p_RECEIVE_DATA (
o_data : out std_logic) is
begin
wait until rising_edge(i2c_clock);
o_data := i2c_data;
wait until falling_edge(i2c_clock);
end procedure P_RECEIVE_DATA;
Now what I want is if an external signal, let's call it r_STOP gets asserted at any time, I want this procedure to exit immediately. Is there a nice way to do this? I was thinking that if this Verilog I could use fork/join_any to accomplish this, but there is no equivalent to fork and join in VHDL. Does anyone have any suggestions?
First of all, the code you have here might be just fine for a test or simulation. If this is what it's for, then great. However, keep in mind that code written as you have above is not synthesizable. You can compile and run it in a simulation setup, but you almost certainly won't be able to turn this into a hardware design for an FPGA, ASIC, or any other type of physical device. (In general, procedures can be used in synthesis only when they are called in a process and have no wait statements (or, less commonly, and only in some tools, when all of the wait statements are exactly the same).)
So to answer exactly what you've asked, the way to break out of a procedure is to call return when the condition you are interested in is met. For example if you wanted a global "r_stop" signal as you suggested make this procedure exit early no matter what whenever it changed to a '1', then you'd look for that explicitly:
procedure p_RECEIVE_DATA (
o_data : out std_logic) is
begin
wait until rising_edge(i2c_clock) or r_stop = '1';
if r_stop = '1' then return; end if;
o_data := i2c_data;
wait until falling_edge(i2c_clock) or r_stop = '1';
if r_stop = '1' then return; end if;
end procedure P_RECEIVE_DATA;
Again, if this is not testbench code, but is meant to be synthesizable, you need to take a different approach and model your logic as an explicit finite state machine.
I'm not sure there's a nice solution to this in VHDL. It's a bit like making an inferred state machine with a reset signal, which is also not pleasant.
You can do:
wait until rising_edge(clk); exit when reset = 1;
within a loop.
I guess you could do:
wait until rising_edge(clk); if stop = '1' then return; end if;
but again, not pleasant!
Here my 2 cents.
You can do this in your main thread/process by calling trigger control signals for those other threads/processes.
Depending on the state of those control signals you can wait for any thread(join_any), all threads(join) or just do not wait (join_none).
Driving signals from multiple processes is a bad idea unless you really know what you're doing (multiple driver problem). Therefore the activation and deactivation signal for each thread should be different since they are controlled from different processes/drivers. That is the reason why i have written 2 control signals 1.started and 2.finished for each thread.
It is very important that a signal/interface is only written in one process in your code.
The code use waits so the same problems stated by wjl are applicable for synthesis.
If you want it synthetizable then put thread_0_active in the sensitivity list and do if rising_edge(thread_0_active) then inside the process. This will encapsulate the code and will be executed only in case of the rising condition. Of course the code inside this process should be synthetizable and contain no waits.
A state machine can only run and be in one state at a time.
I think you are interested on a direct equivalente to the systemverilog fork behavior. I have tried to make the example as close as possible.
The code below:
signal thread_0_started : std_logic:='0';
signal thread_0_finished : std_logic:='0';
signal thread_1_started : std_logic:='0';
signal thread_1_finished : std_logic:='0';
--......
p_main_father : process
variable father_v : std_logic_vector( 32-1 downto 0 );
begin
--Do other things in your main thread using variables
--
--Now fork a thread activating it.
thread_0_started <= '1';
thread_1_started <= '1';
--signals are activated and now we need to wait when they are finished
--here both threads are started at the same time concurrently.
----------------------
--a fork .. join_any would be to do an "or" until the logic
wait until (thread_0_finished = '1') or (thread_1_finished = '1');
-------------------
--a fork .. join would be to do an "and" with the logic
--wait until (thread_0_finished = '0') and(thread_1_finished = '0');
--a fork .. join_none would be to just NOT do "wait until" and ignore that the threads were activated!!!
thread_0_started <= '0';--restore started state in case this main thread want to start them again.
thread_1_started <= '0';
end process;
child_thread_0 : process
variable prdata_v : std_logic_vector( 32-1 downto 0 );
begin
if thread_0_started = '0' then
thread_0_finished <= '0';--important disable finished if not started
end if;
wait until rising_edge(thread_0_started);--trigger event
--Do your things inside de thread_0 that consume time. e.g. calling other process
thread_0_finished <= '1';
end process;
child_thread_1 : process
variable prdata_v : std_logic_vector( 32-1 downto 0 );
begin
if thread_1_started = '0' then
thread_1_finished <= '0';--important disable finished if not started
end if;
wait until rising_edge(thread_1_started);
--Do your things inside de thread_1 that consume time. e.g. calling other process
thread_1_finished <= '1';
end process;

Resources