The VHDL code below is a simple swap program. But it is not swapping the inputs a and b. I have given the transcript values in the comments.
library ieee;
use ieee.std_logic_1164.all;
entity vhdl_swap is
port(a,b: inout integer);
end vhdl_swap;
architecture ar of vhdl_swap is
signal s : std_logic;
begin
process(s)
variable var : integer:=0;
begin
report "var is" & integer'image(var); -- 0
report "a is " & integer'image(a); -- 10 - (given value when simulated)
report "b is " & integer'image(b); -- 20 - (given value when simulated)
report "---------------------------";
var := a;
report "var is " & integer'image(var);--var = 10 (assigned properly)
a<=b;
report "a is " & integer'image(a);-- a=10(same value but not assigned)
b<=var;
report "b is " & integer'image(b);-- b=20(same value but not assigned)
report "-----------------------------------";
report "a is " & integer'image(a);--a=10
report "b is " & integer'image(b);--b=20
--print()
end process;
end;
There is something which acts in the statement a<=b, but i don't know what prevents itself from assigning it.
The new value assigned with VHDL <= is not available for read until an delta delay has passed.
This is a fundamental property of VHDL, since it reflects the way register update works then the signal that triggers the update is a clock.
This also means that you can actually do the swap without a variable, but simply doing:
a <= b;
b <= a;
There are other issues with the code, e.g. what is the s used for, using a and b for both input and output will give a drive conflict, unless resolution function is added.
If you assign a new value to a signal in VHDL with <= without giving an explicit delay (with after <time>), then the new signal value will be available in the next delta cycle. A new delta cycle starts, when the simulator has suspended all processes which have been scheduled for the current delta cycle. And a process is suspended at a wait statement. Your process has an implicit wait on S; statement at the end, because you described a process with a sensitivity list containing S.
You assigned the inout ports a and b here which behave the same as a signal.
Because, the signal update is visible not until the next delta cycle, all your report statements print out the same value for a and b respectively. That is, they print out the values of a and b when the process has started / resumed.
Assigning a signal is different to assigning a variable, e.g. var in your code, which gets updated immediately.
Your process is executed only once, because the signal S is not changed. Every process is executed once after the simulation starts and then suspended at the wait statement (the implicit one in your code as described above).
You said, that a and b have the initial value of 10 and 20, respectively, but I couldn't reproduce this with ModelSim nor GHDL. I tried it with the following testbench which I think is the only possible way:
library ieee;
use ieee.std_logic_1164.all;
entity vhdl_swap_tb is
end entity vhdl_swap_tb;
architecture sim of vhdl_swap_tb is
-- component ports
signal a : integer := 10;
signal b : integer := 20;
begin -- architecture sim
-- component instantiation
DUT: entity work.vhdl_swap
port map (
a => a,
b => b);
end architecture sim;
I had to use initial values for a and b here, because both ports of mode inout and of an unresolved type. Thus, I cannot add a second driver by assigning a and b in another testbench process.
Because, the signal updates are delayed (at least) until the next delta cycle, you do not need an extra variable. Here is a very short example code demonstrating the swapping of two signals:
library ieee;
use ieee.std_logic_1164.all;
entity swap is
end entity swap;
architecture sim of swap is
signal a : integer := 10;
signal b : integer := 20;
signal clock : std_logic := '1';
begin
-- clock generation
clock <= not clock after 10 ns;
-- swapping
process(clock)
begin
if rising_edge(clock) then
a <= b;
b <= a;
end if;
end process;
end sim;
The swapping is done at every rising edge of the clock, as can be seen in the following waveform:
Related
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.
I have a baffling problem.. As part of a buffering process I am assigning one std_logic_vector to another, by simply doing:
dataRegister <= dataRegisterBuf;
The process is synced to a clock. See here for the full process:
--! This process buffers the data register synced to sclk when state is state_bufferingToSclk and sets registerReady when done
SclkDomainBuffering: process(sclk)
variable step: natural := 0;
begin
if (rising_edge(sclk)) then
if (state = state_bufferingToSclk) then
if (step = 0) then
dataRegister <= dataRegisterBuf;
step := 1;
elsif (step = 1) then
registerReady <= '1';
step := 2;
end if;
else
step := 0;
registerReady <= '0';
end if;
end if;
end process SclkDomainBuffering;
The problem is, when simulating this in Modelsim, dataRegister does not take the value of dataRegisterBuf, instead every '1' in the vector becomes 'X'. So for example if dataRegisterBuf is "00010", dataRegister becomes "000X0". I can't for the life of me figure out why. Here is a simulation showing it happening: http://i.imgur.com/znFgqKl.png
I have stepped through the entire code and I can't see anything out of the ordinary. At the time it happens, line 84 in the code above does indeed execute, and that is the only statement that is executed that has anything to do with the two registers in question as far as I can tell.
Here's a Minimal Complete and Verifiable example created from your question and comments:
library ieee;
use ieee.std_logic_1164.all;
entity baffling_problem is
end entity;
architecture foo of baffling_problem is
type state_type is (state_bufferingToClk, state_bufferingToSclk);
signal state: state_type; -- defaults to 'LEFT, state_bufferingToClk
signal dataRegisterBuf: std_logic_vector (31 downto 0) :=
(1 | 2 => '1', others => '0');
signal dataRegister: std_logic_vector (31 downto 0) := (others => '0');
signal registerReady: std_logic;
signal sclk: std_logic := '1';
begin
SclkDomainBuffering: process(sclk)
variable step: natural := 0;
begin
if (rising_edge(sclk)) then
if (state = state_bufferingToSclk) then
if (step = 0) then
dataRegister <= dataRegisterBuf;
step := 1;
elsif (step = 1) then
registerReady <= '1';
step := 2;
end if;
else
step := 0;
registerReady <= '0';
end if;
end if;
end process SclkDomainBuffering;
SOMEOTHERPROCESS:
process (state)
begin
if state = state_type'LEFT then -- other than state_bufferingToSclk
dataRegister <= (others => '0');
end if;
end process;
STIMULI:
process
begin
wait for 20 ns;
sclk <= '0';
wait for 5 ns;
sclk <= '1';
wait for 0 ns; -- state transitions in distinct delta cycle
state <= state_bufferingToSclk;
wait for 20 ns;
sclk <= '0';
wait for 5 ns;
sclk <= '1';
wait for 20 ns;
wait;
end process;
end architecture;
And this gives the behavior your describe:
See IEEE Std 1076-2008 14.7.3 Propagation of signal values, 14.7.3.1 General:
As simulation time advances, the transactions in the projected output waveform of a given driver (see 14.7.2) will each, in succession, become the value of the driver. When a driver acquires a new value in this way or as a result of a force or deposit scheduled for the driver, regardless of whether the new value is different from the previous value, that driver is said to be active during that simulation cycle. For the purposes of defining driver activity, a driver acquiring a value from a null transaction is assumed to have acquired a new value. A signal is said to be active during a given simulation cycle if
— One of its sources is active.
— One of its subelements is active.
— The signal is named in the formal part of an association element in a port association list and the corresponding actual is active.
— The signal is a subelement of a resolved signal and the resolved signal is active.
— A force, a deposit, or a release is scheduled for the signal.
— The signal is a subelement of another signal for which a force or a deposit is scheduled.
So the signals (dataReady(1) and dataReady(2) are active their sources is active.
An explanation of why their values are the resolved value of their drivers is found in 14.7.3.2 Driving values, none of the signals comprising dataReady are basic signals, see paragraph 3 f).
And why you see the value of dataReady as "00000000000000000000000000000XX0" is described in 14.7.3.3 Effective values.
The VHDL language describes how an elaborated design model is simulated as well as describing the syntax and semantics. An elaborated design model consists of processes described in a hierarchy interconnected by signals, and signals have history not just value. Signal updates are scheduled in projected output waveforms (see 10.5 Signal assignment statement).
A lot of users just starting out in VHDL apply what they know of the behavior of other languages to VHDL, an example is the superfluous (but not forbidden) parentheses surrounding a condition in an if statement. Knowledge of other languages doesn't address signal behaviors (determined by the architecture of simulation models driven by simulation cycles.
One of the things you'll note is that processes (11.3) suspend and resume based on explicit or implicit wait statements (10.2).
All concurrent statements are elaborated into processes and or processes and block statements (11. Concurrent statements).
Subprogram calls are either expressions (functions, 9.3.4) or statements (procedures, 10.7).
No signal value is updated while any process that is scheduled to be active (those projected output waveforms matching the current simulation time, 14.7.4 Model execution, 14.7.3.4 Signal update).
Signals driven in multiple processes represent multiple collections of hardware. The problem shows up because you've used resolved data types, if you had used unresolved data types you would have gotten an elaboration error instead (6.4.2.3 Signal declarations, paragraph 8). Resolved signals are allowed to have multiple drivers.
The resolution table for std_logic elements is found in the package body for package std_logic_1164(See footnote 15 Annex A Description of accompanying files for access to the source of VHDL packages included with the standard). The resolution table will resolve a '0' and a '1' to an 'X'.
And if all this sounds complex you can learn simple rules of thumb to prevent problems.
In this case a rule of thumb would be to always drive a signal from a single process.
As people in the comments said, the problem was that another process was driving the same data register. I did not understand that even though that other process only changed the value of the register in a different state, it would still drive the signal during every other state. I fixed the problem by moving everything related to that register into a single process.
How do I print matrix_a(1,1) on the console? The report command I commented does not work.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity ent is
end ent;
architecture Behavioral of ent is
type my_matrix is array(integer range 0 to 3, integer range 0 to 3) of integer;
signal matrix_a : my_matrix;
begin
matrix_a(1,1) <= 4;
--report "signal signal_d is " & integer'image((matrix_a(1,1)));
end Behavioral;
When do you expect that report to run?
You have placed it in the concurrent statement region of your architecture : everything there is effectively a process, scheduled according to specific rules; for example, the concurrent assignment matrix_a(1,1) <= 4; will run once at startup, and whenever any of its values change (i.e. never again as they are all literal constants).
But there is nothing to make the "report" run.
Now if you embed it explicitly in a process, sensitive to changes in matrix_a, then it will run at start and whenever matrix_a changes. So try this in place of the commented line:
process (matrix_a) is -- this list controls the process running
begin
report "signal signal_d is " & integer'image(matrix_a(1,1));
end process;
In some testbench code I use a procedure to do something with a signal. I then use this procedure multiple times in sequence on different signals. This works fine as long as I explicitly define the signal; as soon as I index signals in a loop it fails with
(vcom-1450) Actual (indexed name) for formal "s" is not a static signal name.
Why is this not possible and how can I work around it?
Probably I could move this to a for ... generate, but then I want do_something to be called in a nicely defined sequence.
library ieee;
use ieee.std_logic_1164.all;
entity test is
end test;
architecture tb of test is
signal foo : std_logic_vector(1 downto 0);
begin
dummy: process is
procedure do_something (
signal s : out std_logic
) is begin
s <= '1';
report "tic";
wait for 1 ns;
-- actually we would do something more interesting here
s <= '0';
report "toc";
end procedure;
begin
-- This works well, but requires manual loop-unrolling
do_something(foo(0));
do_something(foo(1));
-- This should do the same
for i in foo'range loop
-- This is the offending line:
do_something(foo(i));
end loop;
wait; -- for ever
end process dummy;
end architecture tb;
I'm using ModelSim 10.4 PE.
Interestingly, if foo is a variable local to the process, (and s is adjusted to suit) ghdl compiles this. Which highlights the problem in the original version. The "for" loop is required to drive the whole of foo all the time because you can't make signal drivers appear or disappear at will - it can't be ambivalent about which bits it's driving, (and as you can see, the procedure tries to drive different bits at different times).
So if you can readjust your application to allow variable update semantics, and make foo a variable local to the process, that will work. (You would have to copy its value to a signal before every "wait" if you wanted to see the effect!)
Alternatively, pass the entire foo signal and the index to the subprogram, so that the latter always drives all of foo as follows...
(I've also added the missing bits and fixed the spurious concurrent "wait" : in future, PLEASE check your code example actually compiles before posting!)
library ieee;
use ieee.std_logic_1164.all;
entity test is
end test;
architecture tb of test is
signal foo : std_logic_vector(1 downto 0);
begin
dummy: process is
procedure do_something (
signal s : out std_logic_vector(1 downto 0);
constant i : in natural
) is begin
s <= (others => '0');
s(i) <= '1';
report "tic";
wait for 1 ns;
-- actually we would do something more interesting here
s(i) <= '0';
report "toc";
end procedure;
begin
-- This works well, but requires manual loop-unrolling
do_something(foo,0);
do_something(foo,1);
-- This should do the same
for i in foo'range loop
-- This is the offending line:
do_something(foo,i);
end loop;
wait; -- for ever
end process dummy;
end architecture tb;
I share your feelings about this being a silly limitation of the language. Minus the wait and report statements your example certainly has a valid hardware implementation, let alone well defined simulation behavior.
I think this situation can be avoided in most cases. For example, in your simple example you could just copy the contents of the procedure into the process body, or pass the whole vector as Brian proposed. If you really need to do it, this is one workaround:
architecture tb of test is
signal foo : std_logic_vector(1 downto 0);
signal t : std_logic;
signal p : integer := 0;
begin
foo(p) <= t;
dummy: process is
procedure do_something (
signal s : out std_logic
) is begin
s <= '1';
wait for 1 ns;
s <= '0';
end procedure;
begin
for i in foo'range loop
p <= idx;
do_something(t);
wait for 0 ns;
end loop;
wait;
end process dummy;
end architecture tb;
This only works in simulation and will result in one delta cycle delay per iteration, compared to unrolling the loop which finishes in zero time when the procedure contains no wait statements.
If I have the following VHDL-200X architecture:
architecture my_arc of my_entity is
signal test_char : std_logic_vector(7 downto 0);
signal test_char_c : character;
signal test_char_i : integer;
begin
test_char <= "01001010";
test_char_i <= to_integer(unsigned(test_char));
test_char_c <= character'val(test_char_i);
end architecture my_arc;
...and simulate it (in Xilinx iSim 14.1), test_char_c does not change from its initial value of NUL even though test_char_i takes the value 74. If, however, I replace the last line in the architecture with:
process(test_char_i)
begin
test_char_c <= character'val(test_char_i);
end process;
...then test_char_c takes on the value J as I'd expect.
I thought that a bare signal assignment will be updated concurrently if any signal on the right hand side changes. In other words, it's equivalent to a process that is sensitive to all signals involved in the assignment.
Why doesn't test_char_c get updated in the first instance?
Edit: Changing test_char_i to a natural doesn't change the result.
At initialisation time, test_char_i has the value integer'low, which doesn't map to a character - Modelsim 10.0 reports:
# ** Fatal: (vsim-3390) Result ?(-2147483648) of attribute 'VAL is out of range NUL (0) to 'ÿ' (255).
# Time: 0 ns Iteration: 0 Process: /my_entity/line__15 File: attr.vhd
# Fatal error in Architecture my_arc at attr.vhd line 15
#
If I make test_char_i a natural, so that it initialises to 0, things work as you expect (in Modelsim at least, haven't tried iSim)
I thought that a bare signal assignment will be updated concurrently if any signal on the right hand side changes. In other words, it's equivalent to a process that is sensitive to all signals involved in the assignment.
That's correct.
Why doesn't test_char_c get updated in the first instance?
It does.
A Minimal, Complete, and Verifiable example with a monitor process that will report all value updates on test_char_c:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity my_entity is
end entity;
architecture my_arc of my_entity is
signal test_char : std_logic_vector(7 downto 0);
signal test_char_c : character;
signal test_char_i : natural; -- integer;
begin
test_char <= "01001010";
test_char_i <= to_integer(unsigned(test_char));
test_char_c <= character'val(test_char_i);
process (test_char_c)
begin
report "test_char_c = " & character'image(test_char_c);
end process;
end architecture my_arc;
Note the change to the declaration of test_char_i to overcome the default initial value (INTEGER'LOW) causing a bound check failure as reported by Martin Thompson.
This was analyzed, elaborated and simulated using a -1993 compliant VHDL tool:
ghdl -r my_entity
../../src/ieee/numeric_std-body.v93:2098:7:#0ms:(assertion warning): NUMERIC_STD.TO_INTEGER: metavalue detected, returning 0
my_entity.vhdl:19:9:#0ms:(report note): test_char_c = nul
my_entity.vhdl:19:9:#0ms:(report note): test_char_c = 'J'
The assertion warning from package numeric_std is caused by the test_char default intial value of "UUUUUUUU".
The first reported test_char_c value is the NUL you reported and occurs because the initial value of test_char_i is 0 (mapping to NUL).
The second is in response to the concurrent simple signal assignment to test_char resulting in an update of test_char_i in turn resulting in an update of test_char_c(and resuming the monitor process). It reflects the assigned bit string to test_char with a value x"4A" (corresponding to the character 'J').
If instead of the shown monitor process you were to have an assertion statement of the form:
assert test_char_c /= NUL
report "test_char_c = " & character'image(test_char_c);
You'd find that only the first report statement is displayed because an assertion statement condition is evaluated and when found false asserts.
Likewise if the "/=" in the condition were changed to "=" only the second report statement would be displayed (showing 'J').
Without providing a MCVe your problem can't be duplicated (or blamed on the then nascent ISIM).